読者です 読者をやめる 読者になる 読者になる

カリー化

JavaScript Python Gauche

JavaScriptでカリー化

私の第一言語であるJavaScriptでカリー化を試してみる。

JavaScriptはお師匠のJavascriptシェルで実行すると楽ちん。


例題はWikipediaのカリー化を参考にしよう。

関数 f がhttp://upload.wikimedia.org/math/9/3/6/936d3616ae1788839acf2cbb7228fad2.pngの形のとき、f をカリー化したものを g とすると、g はhttp://upload.wikimedia.org/math/8/6/7/8678d9a38b70c18ff730a4326baf87b9.pngの形を取る。非カリー化(uncurrying)とは、これの逆の変換である。

カリー化とは直感的には「引数を幾つか固定すると、残った引数の関数が得られる」ということである。たとえば、除算の関数http://upload.wikimedia.org/math/8/b/0/8b012fa4da01406236b0b0a5cb959a03.pngをカリー化したものを cdiv とし、inv = cdiv(1) とすると、inv は新しい関数となり、http://upload.wikimedia.org/math/d/2/0/d201da20452ac22a913f0debbcdd4dc4.png 、つまり引数の逆数を返す関数になる。

http://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%AA%E3%83%BC%E5%8C%96
実際に書いてみた。

例題を実直にdiv関数を書くとこんな感じ。

var div = function(x,y){
  return x / y;
};
alert(div(4, 2));//2

2つ目の例を落とし込むとこんな感じ。

var inv = function(x){
  return function(y){
    return x / y;
  };
};

var cdiv = inv(10);//inv(10)のfunctionを変数cdivにbindする

alert(cdiv(1));//10
alert(cdiv(2));//5

var cdiv = inv(2);//inv(2)のfunctionを変数cdivにbindする
alert(cdiv(1));//2
alert(cdiv(2));//1

alert(inv(10)(2));//5
alert(inv(10)(5));//2


書いて分かったけど、高階関数の一種なのね。なるほど。

乗法してみた

もう少し書いてみる。次は乗法。

var multiplication_curry = function(x){
  return function(y){
    return x * y;
  };
};

//実行例1
var first = multiplication_curry(1);
var second = multiplication_curry(2);
var third = multiplication_curry(3);
alert(first(second((third(4)))));//24
//first(second((third(4))))
//first(second((3 * 4)))
//first(second((12)))
//first(2 * 12)
//first(24)
//1 * 24
//24

//実行例2: 実行例1とは当然等価。
alert(multiplication_curry(1)(multiplication_curry(2)(multiplication_curry(3)(4))));//24
//multiplication_curry(1)(multiplication_curry(2)(3 * 4))
//multiplication_curry(1)(multiplication_curry(2)(12))
//multiplication_curry(1)(2 * 12))
//multiplication_curry(1)(24))
//1 * 24
//24

展開式も書いてみた。

JavaScriptでこの書き方好きだけど、他人のコードをリバースエンジニアリングするのは勘弁。

Pythonでカリー化

乗法を第2言語のPythonで書いてみる。

multiplication_curry = lambda x: lambda y: x * y

print(multiplication_curry(1)(multiplication_curry(2)(multiplication_curry(3)(4))))#24

lamda式を使う。return文がないので綺麗に書けた。

Gaucheでカリー化

ついでにGaucheでもカリー化。

(define (multiplication_curry x)
        (lambda (y) (* x y)))

((multiplication_curry 1)
        ((multiplication_curry 2)
        ((multiplication_curry 3)
        4)))
;;24

大体理解した。

別件の疑問

JavaScriptの関数定義の際、変数に無名関数を束縛する書き方と関数を定義する書き方どっちが主流なんだろう??

変数に無名関数を束縛する書き方例
var div = function(x,y){
  return x / y;
};
関数の定義
function div(x,y){
  return x / y;
}


個人的には前者の変数に無名関数を束縛する書き方なのだけれど...どっちが良いのだろうか...??


まとめ

  1. カリー化を実戦で使うところってどこだ?
  2. やっぱりプログラミング言語ファーストクラスオブジェクトじゃないと♪

参考

id:m-hiyamaさんのブログを読んでて興味を持ちました。
檜山正幸のキマイラ飼育記

例題はWikipediaからの引用です。
Wikipedia カリー化

実行とテストにはお師匠のJavascriptシェルを利用しました。
Javascriptシェル