Introducing 

Prezi AI.

Your new presentation assistant.

Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.

Loading…
Transcript

いきなりですが、

ソートの比較関数をご存知ですか?

無名関数

さて、

先ほどの比較関数を応用して、

文字列比較を行いましょう。

要求! :

先頭の 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の責任であり、

参考文献の責任ではありません。

Learn more about creating dynamic, engaging presentations with Prezi