カリー化のソースを表示
←
カリー化
ナビゲーションに移動
検索に移動
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループに属する利用者のみが実行できます:
登録利用者
。
このページのソースの閲覧やコピーができます。
'''カリー化''' (currying, カリー化された=curried) とは、複数の[[引数]]をとる[[関数 (プログラミング)|関数]]を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること(あるいはその関数のこと)である。[[クリストファー・ストレイチー]]により論理学者[[ハスケル・カリー]]にちなんで名付けられたが、実際に考案したのはMoses Schönfinkelと[[ゴットロープ・フレーゲ]]である。 ごく簡単な例として、''f''(''a'', ''b'') = ''c'' という関数 ''f'' があるときに、''F''(''a'') = ''g''(ここで、''g'' は ''g''(''b'') = ''c'' となる関数である)という関数 ''F'' が、''f'' のカリー化である。 関数 ''f'' が <math>f:(X \times Y) \to Z</math> の形のとき、<math>f</math> をカリー化したものを <math>g</math> とすると、<math>g:X \to (Y \to Z)</math> の形を取る。uncurryingは、これの逆の変換である。 [[理論計算機科学]]の分野では、カリー化を利用すると、複数の引数をとる関数を、一つの引数のみを取る複数の関数の[[ラムダ計算]]などの単純な理論的モデルと見なして研究できるようになる。[[圏論]]ではカリー化の概念を、[[デカルト閉圏]]における[[冪対象]]の[[普遍性]]に見出せる。適当な2つの[[対象 (圏論)|対象]]の[[積 (圏論)|積]]から別の対象への[[射 (圏論)|射]] <math>f: X \times Y \to Z</math> に対して、射 <math>g: X \to Z^Y</math> が一意に対応する。 カリー化をする現実の動機の1つに、カリー化することで後述する[[部分適用]]が行いやすくなることが挙げられる。たとえば、加算を行う関数 <code>(+)</code> をカリー化してから、最初の引数だけに <code>1</code> を適用すれば、インクリメント用の関数が簡単に作れる。 カリー化を基盤としている[[プログラミング言語]]もある。特に[[ML (プログラミング言語)|ML]]と[[Haskell]]では関数は常に一つの引数のみを取り、複数の引数を取る関数とは、単にネストされた複数の一引数関数の[[糖衣構文]]にすぎない。[[第一級関数]]を扱える言語、たとえば[[LISP]]、[[Scheme]]、[[F Sharp|F#]]、[[Scala]]、[[Erlang]]、[[Eiffel]]、[[Perl]]、[[Ruby]]、[[Python]]、[[R言語]]、[[S言語]]、[[JavaScript]]、[[Swift (プログラミング言語)|Swift]]などでは、カリー化関数を作ることができる。 ==実装例== たとえば、除算の関数 <math>\operatorname{div}(x, y) = x / y</math> をカリー化したものを <math>\operatorname{cdiv}(x)</math> とすると、<math>\operatorname{cdiv}(x)</math> は <math>x</math> のみを引数に取る。そして <math>\operatorname{inv} = \operatorname{cdiv}(1)</math> とすると、<math>\operatorname{inv}(y)</math> は <math>y</math> のみを引数に取る新しい関数となり、<math>\operatorname{inv}(y) = 1 / y</math>、つまり引数の逆数を返す関数になる。 この例をSchemeとJavaScriptで実装した例を示す。 <syntaxhighlight lang="scheme"> (define div (lambda (x y) (/ x y))) ;(div 1 3) == (/ 1 3), これはカリー化ではない。 (define cdiv (lambda (x) (lambda (y) (div x y) ))) ;(cdiv a) == (div a y) ((cdiv 10) 3) ;=> 10/3 (define inv (lambda (x) ((cdiv 1) x))) ;inv == (cdiv 1) (inv 2) ;=> 1/2 </syntaxhighlight> <syntaxhighlight lang="javascript"> function div(x, y) { return x / y; } //div(1, 3) == 1 / 3, これはカリー化ではない。 function cdiv(x) { return function(y) { return div(x, y); } } console.log(cdiv(10)(3)); //=> 10/3 = 3.333... var inv = cdiv(1); console.log(inv(2)); //=> 1/2 = 0.5 </syntaxhighlight> ==部分適用との混同== カリー化は{{ill|部分適用|en|Partial application}}と混同されやすい<ref>http://lambda-the-ultimate.org/node/2266</ref><ref>http://www.uncarved.com/blog/not_currying.mrk</ref>。 部分適用とは、複数の引数をとる関数の一部の引数に実引数を適用する操作のことで、例えば上述の <math>\operatorname{div}(x, y)</math> から <math>\operatorname{inv}(y)</math> を導く操作を指す。部分適用の一例として、[[標準C++ライブラリ]]の <code>std::bind1st</code><ref group="注釈">[[C++11]]で非推奨、[[C++17]]で削除</ref> が挙げられる。 一方、カリー化は例えば上述の <math>\operatorname{div}(x, y)</math> から <math>\operatorname{cdiv}(x)</math> を導く操作であり、引数への実引数の適用までは行わない。 この混同はしばしば言語設計者によってもなされる。[[Groovy]] では、部分適用を行う標準メソッドに <code>curry</code> という名前がつけられており、注意が必要である。 ==タプル引数との関連== [[Haskell]] の標準関数 <code>curry</code> は、カリー化と厳密には違う動作をする{{要出典|date=2020年12月}}。この関数は <code>(a, b) -> c</code> という型を持つ関数を <code>a -> b -> c</code> 型の関数に変換するが、元の関数は「2 要素の[[タプル]]を取る 1 引数関数」であり、2 引数関数ではない。Haskell は全ての関数が 1 引数関数であり(つまり、全ての関数が元々カリー化された形であるとも表現される)、Haskell プログラムでは、厳密な意味でカリー化を行う関数は定義できない。ただし型理論上は、<code>X</code>, <code>Y</code> という型の要素を持つタプルの型は直積 <math>X \times Y</math> とほぼ同一視できるため、必ずしも誤用というわけではない。 ==関連項目== *[[遅延評価]] *[[クロージャ]] *[[s-m-n定理]] == 脚注 == === 注釈 === <references group="注釈" /> === 脚注 === {{脚注ヘルプ}} <references /> {{DEFAULTSORT:かりいか}} [[Category:関数型プログラミング|かりいか]] [[Category:ラムダ計算|かりいか]] [[Category:高階関数]] [[Category:数学のエポニム]] [[Category:数学に関する記事]]
このページで使用されているテンプレート:
テンプレート:Ill
(
ソースを閲覧
)
テンプレート:脚注ヘルプ
(
ソースを閲覧
)
テンプレート:要出典
(
ソースを閲覧
)
カリー化
に戻る。
ナビゲーション メニュー
個人用ツール
ログイン
名前空間
ページ
議論
日本語
表示
閲覧
ソースを閲覧
履歴表示
その他
検索
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
特別ページ
ツール
リンク元
関連ページの更新状況
ページ情報