TL; DR他の人が指摘したように、ラムダ表記は関数に名前を付けずに関数を定義する方法にすぎません。
ロングバージョン
このトピックについて非常に興味深いと思うので、少し詳しく説明したいと思います。免責事項:私はずっと前にラムダ計算のコースを取りました。より良い知識を持つ誰かが私の答えに誤りを見つけた場合、私がそれを改善するのを手伝ってください。
式、たとえば1 + 2
and から始めましょうx + 2
。1
やなどのリテラルは、特定の固定値にバインドされているため、定数2
と呼ばれます。
などの識別子x
は変数と呼ばれ、それを評価するには、まずそれを何らかの値にバインドする必要があります。したがって、基本的には、x + 1
何x
がわからない限り評価することはできません。
ラムダ表記は、特定の入力値を変数にバインドするためのスキーマを提供します。ラムダ式を添加することによって形成することができλx .
、例えば、既存の発現の前にλx . x + 1
。変数x
は自由でx + 1
、束縛されていると言われていますλx . x + 1
これは式の評価にどのように役立ちますか?そのように値をラムダ式にフィードすると
(λx . x + 1) 2
次に、変数のすべての出現をx
値2で置換(バインド)することにより、式全体を評価できます。
(λx . x + 1) 2
2 + 1
3
そのため、ラムダ表記は、式/プログラムブロックに現れる変数に物事をバインドするための一般的なメカニズムを提供します。これは、コンテキストに応じて、プログラミング言語で見かけの異なる概念を作成します。
- Haskellのような純粋に機能的な言語では、ラムダ式は数学的な意味で関数を表します。入力値がラムダの本体に注入され、出力値が生成されます。
- 多くの言語(JavaScript、Python、Schemeなど)では、ラムダ式の本体を評価すると副作用が生じる可能性があります。この場合、プロシージャという用語を使用して、純関数との違いをマークできます。
違いは別として、ラムダ表記は、仮パラメータを定義し、実際のパラメータにバインドすることに関するものです。
次のステップは、関数/プロシージャに名前を付けることです。いくつかの言語では、関数は他の関数と同様の値なので、次のように関数に名前を付けることができます。
(define f (lambda (x) (+ x 1))) ;; Scheme
f = \x -> x + 1 -- Haskell
val f: (Int => Int) = x => x + 1 // Scala
var f = function(x) { return x + 1 } // JavaScript
f = lambda x: x + 1 # Python
Eli Barzilayが指摘したように、これらの定義は名前f
を値にバインドするだけで、これはたまたま関数です。この点で、関数、数値、文字列、文字はすべて、同じ方法で名前にバインドできる値です。
(define n 42) ;; Scheme
n = 42 -- Haskell
val n: Int = 42 // Scala
var n = 42 // JavaScript
n = 42 # Python
これらの言語では、より馴染みのある(しかし同等の)表記を使用して、関数を名前にバインドすることもできます。
(define (f x) (+ x 1)) ;; Scheme
f x = x + 1 -- Haskell
def f(x: Int): Int = x + 1 // Scala
function f(x) { return x + 1 } // JavaScript
def f(x): return x + 1 # Python
Cなどの一部の言語は、(名前付き)関数を定義するための後者の表記法のみをサポートしています。
閉鎖
閉鎖に関するいくつかの最終的な観察。式を考えてくださいx + y
。これには2つの自由変数が含まれます。x
ラムダ表記を使用してバインドすると、次のようになります。
\x -> x + y
まだ無料の変数が含まれているため、これは(まだ)関数ではありませんy
。y
同様にバインドすることで、それから関数を作成できます。
\x -> \y -> x + y
または
\x y -> x + y
これは+
関数とまったく同じです。
ただしy
、別の方法でバインドすることもできます(*):
incrementBy y = \x -> x + y
関数incrementByを数値に適用した結果はクロージャー、つまりy
クロージャーが定義された環境からの値にバインドされた自由変数(など)を本体に含む関数/プロシージャです。
だから、incrementBy 5
5で数字をインクリメント機能(閉鎖)です。
注意 (*)
私はここで少し浮気しています:
incrementBy y = \x -> x + y
と同等です
incrementBy = \y -> \x -> x + y
そのため、バインディングメカニズムは同じです。直感的に、クロージャーはより複雑なラムダ式のチャンクを表すと考えています。この表現が作成されるとき、マザー式のバインディングのいくつかはすでに設定されており、クロージャは後で評価/起動されるときにそれらを使用します。