Hatena::ブログ(Diary)

お前の血は何色だ!! 4 このページをアンテナに追加 RSSフィード Twitter

2010-06-11

いろんな言語のラムダ式とキャプチャ

javaの無名関数disられているらしいので他の言語と比較してみた。

http://www.infoq.com/jp/news/2010/06/lambda-syntax-debate

引数整数型を取り + 1 して返す無名関数を定義してみる。

目的は 72 という数字を 変数 i に格納すること。

なるだけ省略表記を使わないで作るよ。

間違っていたらごめんね!!

いろいろ間違っていたので結構直しました!!

java

・無名ではない関数の場合

int f(int x)
{
	return x + 1;
}

・定義してから呼ぶ

#int(int) f = #(int x)(return x + 1);
int i = f.(71);  //f「.」(71) となっているところが特徴的

・↑を省略化して書く

#int(int) f = #(x)(x + 1);
int i = f.(71);

・定義と同時に直接呼ぶ

int i = #(int x)(return x + 1).(71);

・おまけ:キャプチャ

、、、どうやるんだろう。

多分こんな感じすか?

int cap = 1;
int cap2 = cap;
#int(int) f = #(int x)(return x + 1 + cap2);
cap = -100; //ぶっ壊す
int i = f.(70);

参考:

http://mail.openjdk.java.net/pipermail/lambda-dev/attachments/20100212/af8d2cc5/attachment-0001.txt

注意:

動く実装がないから間違っているかも知れぬ。

C++0x

・無名ではない関数の場合

int f(int x)
{
	return x + 1;
}

・定義してから呼ぶ

std::function<int (int)> f =  [](int x) -> int { return x + 1; };
int i = f(71);

//iの値は 72

・↑を省略化して書く

auto f =  [](int x) -> int { return x + 1; };
int i = f(71);

//iの値は 72

・定義と同時に直接呼ぶ

int i = ([](int x) -> int { return x + 1; })(71);

//iの値は 72

・おまけ:キャプチャ

int cap = 1;
auto f =  [cap](int x) -> int { return x + 1 + cap; };
cap = -100;	   //ぶっ壊す
int i = f(70); //だけど保持される

//iの値は 72

参考

http://ja.wikipedia.org/wiki/C%2B%2B0x#.E3.83.A9.E3.83.A0.E3.83.80.E9.96.A2.E6.95.B0.E3.81.A8.E3.83.A9.E3.83.A0.E3.83.80.E5.BC.8F

http://codezine.jp/article/detail/4035


C# (3.0以上)

・無名ではない関数の場合

int f(int x)
{
	return x + 1;
}

・定義してから呼ぶ

Func<int, int> f = x => { return x + 1; };
int i = f(71);

//iの値は 72

・↑を省略化して書く

Func<int, int> f = x => x + 1;
int i = f(71);

//iの値は 72

・定義と同時に直接呼ぶ

int i = ((Func<int, int>)(x => { return x + 1; }))(71);

//iの値は 72

・おまけ:キャプチャ

、、、、どうやるんだろう?

//これでは無理でした。
int cap = 1;
Func<int, int> f = x => { return x + 1 + cap; };
cap = -100;	   //ぶっ壊す
int i = f(70); // 70 + 1 + 1 ではなく、 70 + 1 + (-100) で -29 になってしまう

//iの値は -29

これらは参照で渡されるので事前に別名に保存すればOKらしい。

int cap = 1;
int cap2 = cap;
Func<int, int> f = x => { return x + 1 + cap2; };
cap = -100;	   //ぶっ壊す
int i = f(70); 

//iの値は 72

参考:

http://ufcpp.net/study/csharp/ap_ver3.html


PHP (5.3以上)

・無名ではない関数の場合

function f($x)
{
	return $x + 1;
}

・定義してから呼ぶ

$f = function($x)
{
	return $x + 1;
};
$i = $f(71);

//iの値は 72

・定義と同時に直接呼ぶ

、、、、どうやるんだろう?

//これはエラーになる。
$i = (function($x){ return $x + 1; })(71);

・おまけ:キャプチャ

$cap = 1;
$f = function($x) use($cap) 
{
	return $x + 1 + $cap;
};
$cap = -100; //ぶっ壊す
$i = $f(70); //だけど保持される

//$iの値は 72

参考:

http://php.net/manual/ja/functions.anonymous.php

javascript

無名ではない関数の場合

function f(var x)
{
	return x + 1;
}

・定義してから呼ぶ

var f = function(x)
{
	return x + 1;
}
var i = f(71);

//iの値は 72

・定義と同時に直接呼ぶ

var i = (function(var x){ return x + 1; })(71);

//iの値は 72

・おまけ:キャプチャ

、、、、どうやるんだろう?

//これではキャプチャできない。。。
var cap = 1;
var f = function(x)
{
	return x + 1 + cap;
}
cap = -100; //ぶっ壊す
var i = f(70); // 70 + 1 + 1 ではなく、 70 + 1 + (-100) で -29 になってしまう

//iの値は -29

コレも同じく別名に保存しておく。

var cap = 1;
let cap2 = cap;
var f = function(x)
{
	return x + 1 + cap2;
}
cap = -100; //ぶっ壊す
var i = f(70);

//iの値は 72

テスト環境: SpiderMonkey 1.8.0

まとめ

//java
#int(int) f = #(int x)(return x + 1);
int i = f.(71);  //f「.」(71) となっているところが特徴的

//C++0x
auto f =  [](int x) -> int { return x + 1; };
int i = f(71);

//C#
Func<int, int> f = x => x + 1;
int i = f(71);

//PHP
$f = function($x)
{
	return $x + 1;
};
$i = $f(71);

//javascript
var f = function(x)
{
	return x + 1;
}
var i = f(71);

どーでもいいけど、無名関数って、無名剣無明剣(ロマサガの最強の大剣技)と名前がかぶっていてかっこいいよね!!

f:id:rti7743:20100612061414p:image無名関数!!

にはには 2010/06/12 13:06 C++0x の例は値のコピーをキャプチャしています。よって元の変数を破壊してもラムダ式のキャプチャしている値に影響は出ないわけです。C++0x でも & を使うことで参照をキャプチャすることができますが、GC なんて当然ないので参照先の寿命には十分に気をつける必要はあります。
C# や javascript の例は、参照をキャプチャしています。なので、キャプチャができていないわけではないです。

rti7743rti7743 2010/06/12 21:13 なるほど。
これらは C++0x での [&]() とされているようなものですか?
参照ではなく、コピーして渡す方法はあるんでしょうか?

直前に自分でコピーするしかないですか?

//事後だとダメ
int cap = 1;
Func<int, int> f = x => { int cap2 = cap; return x + 1 + cap2; };
cap = -100; //ぶっ壊す
int i = f(70);

//事前に別名に保存すればOK
int cap = 1;
int cap2 = cap;
Func<int, int> f = x => { return x + 1 + cap2; };
cap = -100; //ぶっ壊す
int i = f(70);

にはには 2010/06/13 01:27 C# には詳しくないのですが、結局キャプチャするのは値型だろう何だろうと参照なので、共有したくないということならコピーしてやるしかないと思います。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/rti7743/20100611/1276289872