最近「実践F#」を教材に F# User Group - Japan の小泉さんのF#勉強会に参加してるのですが、F#かっけー!と思ったので紹介したいです。先週が1〜3章で、今週は4章が範囲。
たとへばF#ではこんなふうにコードを書くことができます。
> let f x y z = x + y + z ;; val f : int -> int -> int -> int > f 2 5 7 ;; val it : int = 14
>
ではじまってる行が対話環境に打ち込んだコードで、val
ではじまってる行が結果を返す行、といふことでひとつ。
つまるところ、JavaScriptで見た目上に等価な書き方をすると、こんな感じ。Google ChromeのJavaScriptコンソールですね。
>f = function(x,y,z){return x + y + z}; function(x,y,z){return x + y + z} >f(2,5,7); 14
この程度ならJavaScriptがちょっと冗長ってだけで、同じことができてるのがわかりますね。
……と見せかけて、実は全然違ってる。
> let g = f 33 66 ;; val g : (int -> int) > g 1 ;; val it : int = 100
これは何かと見てみると、変数gに函数が入ってます*1。で、最後に 1 を渡してやると*2、みっつの数が足されて100が返ってくる!素敵!
一方でJavaScriptで引数をふたつしか渡さないなんてことをやると…
>g = f(33,66) NaN
NaN(Not a Number)と怒られるだけです。当たり前ですな。
実はさっきのコードを「見かけ」ではなくて「意味的」に書き直してみると、こんな感じ。
f = function(x){ return function(y){ return function(z){ return x + y + z; } } } g = f(33)(66); g(1); f(33)(66)(99);
うん、長いし函数の呼び出し方が変っちゃってますね……。めんどい!
実はF#の函数に渡せる引数はひとつだけで、JavaScriptの例で示した様にF#で「複数の引数が渡された」ふうに見えた函数は、ひとつひとつが函数の入れ子になってたのです。
JavaScriptでは「複数の引数をとる函数」と「複数の函数が入れ子になった函数」では呼び出し方がまるで異なりますが、F#では空白区切りで値を並べるだけです。
こんな函数を「カリー化函数」と呼ぶらしいです。めちゃかっけーです。
僕はRubyKaigiからの帰りの飛行機でこれを読んで、すげーすげーかっけーすげー!と年甲斐もなくはしゃいでたのでした。ほんとの話。
非常に説明不足感がきついので、ぜひ自らF#に触れてみることをたいへんおすすめします。
RubyKaigiつながりでRubyの話をしておくと、実はRubyではこんなコードが書けます。
001:>> f = ->(x, y, z){ x + y + z } => #<Proc:0x000001010483f8@(irb):1 (lambda)> 002:>> g = f.curry[33][66] => #<Proc:0x00000101040338 (lambda)> 003:>> g[1] => 100
F#より冗長ですが、これはこれでかっけーです。