私は ML をまったく知らないので、別の関数型プログラミング言語である Scheme で答えます。あなたがSchemeを知らないと仮定して、私のコードによくコメントします。
**注: スキームは動的に型付けされるため、型宣言 (int、float、char など) は表示されません。
(define (double x) ;this defines a new function called "double" which takes one argument called x
(* 2 x)) ;return 2 times its argument. Function application in Scheme takes the form (function arg1 arg2 ...)
この新しく定義された関数を次のように使用します。
(double 10) ;returns 20
(double 8) ;returns 16
この関数では、変数x
はローカル変数です。x
double の仮パラメータです。x
double の本体で使用するときはいつでも、意味する値に疑いの余地はありません。しかし、これはどうですか:
(define (foo x) ;define a function "foo" which takes on argument called x
(* x a)) ;return x times a
繰り返しますが、x
は仮パラメーターです。しかし、どうa
ですか?a
foo の本体で使用するとはどういう意味ですか? は foo で定義されていないため、自由変数a
と呼ばれます。その意味を理解するには、foo の外を見る必要があります。たとえば、foo が次のコンテキストで定義されているとします。a
(define (bar a) ;define a function "bar" which takes one argument called "a"
(define (foo x) ;define "foo" as an inner function of bar
(* x a))) ;foo returns x * a
今、私たちは何a
を意味するかを知っています。Scheme (および ML) はlexically-scopedです。つまり、変数が何を意味するかa
を調べるには、テキストのコンテキストを調べます (うまくいけば、これは理にかなっています)。
Now, the above definition of bar
is actually incorrect: even thought foo
returns something, bar
doesn't return anything. It defines foo
as an inner function, but then there is no statement following that definition. Let's fix that:
(define (bar a) ;define a function "bar" which takes one argument called "a"
(define (foo x) ;define "foo" as an inner function of bar
(* x a)) ;foo returns x * a
foo) ;bar returns the function foo
Now, bar
returns the function foo
. We have just turned bar
into a higher-order function, because it returns another function.
But there's a problem. Normally, when bar
returns, the local variable a
is no longer needed, and its value is lost. But foo
still makes a reference to a
! So a
needs to stick around for a while longer. This is where closures come in. The value of a
is "closed over", so it sticks around for as long as the function foo
exists. That way, we can call foo
even after bar
has finished execution. Now, let's rename foo
and bar
to see why this is useful:
(define (make-multiplier a)
(define (multiplier x)
(* x a))
multiplier)
Now, we can do this:
(define triple (make-multiplier 3)) ;call make-multiplier with the value 3. Bind the function which is returned to the variable "triple."
(triple 5) ;call triple with the value 5. Since the 3 was "closed over", (triple 5) returns 5 * 3, which is 15.
So - when a function has a "free variable", a closure is created for the function which "closes over" the free variable and preserves it for the lifetime of the function. That way, when the function is passed around and leaves the context it was defined in, the "free variable" continues to be valid.