Introducing
Your new presentation assistant.
Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.
Trending searches
いきなりですが、
ソートの比較関数をご存知ですか?
無名関数
さて、
先ほどの比較関数を応用して、
文字列比較を行いましょう。
要求! :
先頭の 2文字で比較してほしい。
//z「a」r < j「p」y で比較するので、
// -1 が帰ってくる。
alert( func("jpy","zar") );
問題は、
2文字目だということを
比較関数にどう伝えるか。
とりあえず、
2文字目で
ハードコーディング
してみよう。
できるよ、
そう、クロージャならね。
n文字目で比較する関数を返す関数
function make_compare(n)
{
return function(a,b)
{
//n文字目で比較
var aa = a[n] || "";
var bb = b[n] || "";
if (bb == aa)
{
return 0;
}
else if (bb < aa)
{
return -1;
}
else
{
return 1; //bb > aa
}
};
}
var func = make_compare(1);
//z「a」r < j「p」y で比較するので、 -1 が帰ってくる。
alert( func("jpy","zar") );
あれ!?
(つд⊂)ゴシゴシ
n のスコープってどこ?
(;゚ Д゚) …!?
n文字目で比較する関数を返す関数
function make_compare(n)
{
return function(a,b)
{
//n文字目で比較
var aa = a[n] || "";
var bb = b[n] || "";
if (bb == aa)
{
return 0;
}
else if (bb < aa)
{
return -1;
}
else
{
return 1; //bb > aa
}
};
}
var func = make_compare(1);
//z「a」r < j「p」y で比較するので、 -1 が帰ってくる。
alert( func("jpy","zar") );
この状態を
「変数 n が
関数に束縛(bind/capture)
されている。」
とかいいます。
こんなふうに関数を返す関数の中で、
変数を束縛(bind/capture)するものを
クロージャと呼びます。
ちなみに、
参照だけではなく、
書き込みも可能です。
呼び出すたびに
カウントアップしていく関数を作成する
function make_countup(first)
{
var c = first;
return function()
{
c += 1;
return c;
};
}
//最初は10
var func = make_countup(10);
alert( func() ); //10 + 1 で 11
alert( func() ); //11 + 1 で 12
alert( func() ); //12 + 1 で 13
ここまでのまとめ。
直前にならないと
決まらない値以外を
事前に設定できないか?
javascript では無理なんだけど、
配列リストから検索する関数を
考えます。
//検索する
ArraySearch
(検索するもの,検索されるもの,オプション) ;
オプションは予め決まっている。
検索するものと、
検索されるものは、
使用する直前まで定まらない
検索されるものとオプションを固定化して1パラメータにしてみる(カリー化)
おまけ
いろんな言語のクロージャ
モダンな言語には、
たいていクロージャが実装されています。
えんいー
function compare(a,b)
{
return (b - a):
}
Array.sort(compare)
これで何が嬉しいか?
何で毎回
定義しないとダメなの?
関数ですが、名前がありません。
いわば「ななしさん」状態です。
こーゆー関数を無名関数と呼びます。
ソートの比較関数
そこで
無名関数(ラムダ式)ですよ。
javascript で遊ぶ
ラムダ式、クロージャ、カリー化
逆にするのも楽だし。
function compare(a,b)
{
// return (b - a):
return (a - b):
}
Array.sort(compare)
確かにコレは便利なんだけど、
だけど比較関数を
いちいち定義するのが
メンドイ。
//比較関数
function compare(a,b)
{
return (b - a):
}
//ソートする
Array.sort(compare)
ソートするときの
比較用の関数を別に定義できる。
アウトソースできる。
Array.sort(比較関数)
//比較関数
function compare(a,b)
{
return (b - a):
}
//ソート実行
Array.sort(compare)
by rti.
Array.sort(
function(a,b)
{
return (b - a):
}
);
λ
compareって
使い捨ての関数ぢゃないですか。
ソートでしか使わないし、、、
ハーフライフではなく、
ラムダです。
Array.sort(
function(a,b)
{
return (b - a):
}
);
汎用性の確保
利点:
使う場面で
簡単に定義できること。
クロージャ
n文字目で比較する関数を返す関数
function make_compare(n)
{
return function(a,b)
{
//n文字目で比較
var aa = a[n] || "";
var bb = b[n] || "";
if (bb == aa)
{
return 0;
}
else if (bb < aa)
{
return -1;
}
else
{
return 1; //bb > aa
}
};
}
var func = make_compare(1);
//z「a」r < j「p」y で比較するので、 -1 が帰ってくる。
alert( func("jpy","zar") );
逆にしたいなー
function compare(a,b)
{
// return (b - a):
return (a - b):
}
Array.sort(compare)
Array.sort(
function(a,b)
{
return (b - a):
}
);
もう一度よく眺める。
無名関数は、
変数に代入したり、
戻り値に返せたりします。
引数のN
これがクロージャ。
キリッ
変数 n を束縛(bind)している
ここでも有効
・無名関数とは
使い捨ての名前のない関数
・関数を返す関数
その名の通り、
関数を戻り値で返す関数。
・クロージャ
関数を返す関数の中で、
変数を束縛(bind/capture)
する関数。
n文字目で比較する関数を返す関数
function make_compare(n)
{
return function(a,b)
{
//n文字目で比較
var aa = a[n] || "";
var bb = b[n] || "";
if (bb == aa)
{
return 0;
}
else if (bb < aa)
{
return -1;
}
else
{
return 1; //bb > aa
}
};
}
var func = make_compare(1);
//z「a」r < j「p」y で比較するので、 -1 が帰ってくる。
alert( func("jpy","zar") );
//変数に代入もできます。
var func = function(a,b){ return (b - a): };
//変数から呼び出せます。
alert( func(1,2) ); // 2 - 1 で 1 が表示される。
//return で戻り値として返せます。
return func;
return したときにも
n は消えていない。
この娘はクローディア
return の戻り値で関数が返せる
ということは、
こういうことができますね。
クロージャ
なんかいけていない。
もっと一般化できないの?
function make_compare()
{
return function(a,b)
{
//とりあえずどコーディング
var aa = a[1] || ""; //短い文字は ""
var bb = b[1] || "";
if (bb == aa)
{
return 0;
}
else if (bb < aa)
{
return -1;
}
else
{
return 1; //bb > aa
}
};
}
var func = make_compare();
//z「a」r < j「p」y で比較するので、 -1 が帰ってくる。
alert( func("jpy","zar") );
文字列の比較を行う。
function make_compare()
{
return function(a,b)
{
if (b == a)
{
return 0;
}
else if (b < a)
{
return -1;
}
else
{
return 1; //b > a
}
};
}
var func = make_compare();
//"zar" > "jpy" で1が帰ってくる。
alert( func("jpy","zar") );
//ソースコードで説明
function make_countup(first)
{
var c = first;
return function()
{
c += 1;
return c;
};
}
//最初は10
var func = make_countup(10);
alert( func() ); //10 + 1 で 11
alert( func() ); //11 + 1 で 12
alert( func() ); //12 + 1 で 13
N文字目でソートとか
できないの?
関数を返す関数
function make_compare()
{
return function(a,b)
{
return (b - a):
};
}
//関数を受け取る
var func = make_compare();
//実行
// 2 - 1 で 1 が表示される。
alert( func(1,2) );
jpy(円) 日本円
zar(ざー) 南アフリカランド
クロージャと関数を返す関数の違い
変数を束縛するか
しないかの違い。
これとは何が違うの?
クロージャと関数を返す関数の違い
引数をより簡略化した関数を
動的に作成することができました。
オプションは
事前に決まる、
このようにクロージャ等を利用して関数
の引数の数の少ない関数を作ることを
オプションだけを固定化してみる(関数の部分適応)
関数の部分適応とカリー化
「関数の部分適用」
まとめ終わり。
検索するものと、
検索されるものは、
直前になるまで決まらない。
function ArraySearch2
(検索するもの,検索されるもの)
{
return
ArraySearch(検索するもの,
検索されるもの,
オプション決め打ち);
}
と呼びます。
function transArraySearch(オプション)
{
return
function(検索するもの,検索されるもの)
{
return ArraySearch
(検索するもの,検索されるもの,オプション)
};
}
クロージャを利用した
面白い例として、
関数の引数を
少なくすることが出来ます。
function transArraySearch(オプション)
{
return
function(検索するもの,検索されるもの)
{
return ArraySearch
(検索するもの,検索されるもの,オプション)
};
}
//ただの関数を返す関数
function make_add()
{
return function()
{
return a + b;
};
}
//クロージャを返す関数
function make_add()
{
var n = 10;
return function()
{
return a + b + n;
};
}
また、「関数の部分適用」の中でも、
関数の引数をひとつだけにする行為を
クロージャはすごい。←結論
nを束縛するので
クロージャ
ArraySearch(検索するもの,検索されるもの,オプション);
「カリー化」
これだと、オプションが決め打ちになってしまい、
あとで別のオプションに変更することができない。
と呼びます。
//フルで呼び出す.
ArraySearch(検索するもの,検索されるもの,オプション)
//関数の部分適応をやってみる.
var newArraySearch = transArraySearch(MY_OPTION);
~なにか処理~
newArraySearch(検索するもの,検索されるもの); //オプションが消えた.
検索されるものとオプションを固定化して1パラメータにしてみる(カリー化)
カリー化についての疑問あれこれ
まとめ
検索内容は、
残すパラメータは最初のパラメータでなければいけない?
--> No. 第二引数とかを残してもいいらしい。
ただ、大抵のカリー化は最初の引数を残している。
事前に決まる
クロージャを利用し、関数の部分適応を利用すると、
引数を少なくした関数を動的に作成することができます。
この引数の数の少ない関数を作ることを関数の部分適用といい
ます。
検索するものは
ArraySearch(検索するもの,検索されるもの,オプション)
↓
curreyArraySearch(検索するもの)
function curryArraySearch(検索されるもの,オプション)
{
return function(検索するもの)
{
return
ArraySearch(検索するもの,検索されるもの,オプション)
};
}
var f = curryArraySearch(検索されるもの,MY_OPTION);
f(検索するもの);
ArraySearch(検索するもの,検索されるもの,オプション)
↓
newArraySearch(検索するもの,検索されるもの)
直前になるまで
決まらない
//これでもOK
ArraySearch(検索するもの,検索されるもの,オプション)
↓
curreyArraySearch(検索されるもの)
関数の部分適応の中で、
関数の引数を1引数にすることをカリー化といいます。
ArraySearch(検索するもの,検索されるもの,オプション);
//これはダメ. 2引数なので関数の部分適応
ArraySearch(検索するもの,検索されるもの,オプション)
↓
curreyArraySearch(検索するもの,検索されるもの)
ArraySearch(検索するもの,検索されるもの,オプション)
↓
curreyArraySearch(検索するもの)
引数が1パラメータの関数を動的につくることができました。
この行為をカリー化といいます。
参考文献
・C++ (C++0x以上)
int cap = 1;
auto f = [cap](int x) ->
int { return x + 1 + cap; };
int i = f(70); //72
・C# (3.0以上)
int cap = 1;
Func<int, int> f = x => x + 1 + cap;
int i = f(70); //72
・PHP (5.3以上)
$cap = 1;
$f = function($x) use($cap)
{
return $x + 1 + $cap;
};
$i = $f(70); //72
・java(次期バージョン)
int cap = 1;
#int(int) f = #(x)(x + 1 + cap);
int i = f.(70); //72
JavaScriptでカリー化 / 檜山正幸のキマイラ飼育記
http://d.hatena.ne.jp/m-hiyama/20051213/1134446855
猿でもわかるクロージャ超入門 / DQNEO起業日記
http://dqn.sakusakutto.jp/2009/01/javascript.html
http://favotter.net/status.php?id=15562586819
http://favotter.net/status.php?id=15563705748
http://favotter.net/status.php?id=15562979662
いろんな言語のラムダ式とキャプチャ
http://d.hatena.ne.jp/rti7743/20100611/1276289872
ただのクロージャとカリー化の違いがよくわからない
http://d.hatena.ne.jp/rti7743/20100505/1273011836
http://twitter.com/#!/kinaba/status/15562586819
このスライドの誤りはrtiの責任であり、
参考文献の責任ではありません。