0

私は ML を使用するクラスを受講しており、クロージャーについて調べていますが、特に ML についてはよくわかりません。授業中にメモを取りましたが、あまり意味がありません/十分な詳細が得られません。詳細については、オンラインで調べてみましたが、何も見つかりませんでした。

ML のクロージャー (または ML/クロージャー全般) に関する非常に優れたリソースを知っている人はいますか?

または、誰かが ML でクロージャを実装する方法や、ML でクロージャがどのように見えるか、クロージャとは何かなどについて、いくつかの一般的な考えや説明を投稿できれば、本当に感謝しています。クロージャーの概念/使用法を理解しようとしています。

前もって感謝します!

4

2 に答える 2

1

私は 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ローカル変数ですxdouble の仮パラメータです。xdouble の本体で使用するときはいつでも、意味する値に疑いの余地はありません。しかし、これはどうですか:

(define (foo x)          ;define a function "foo" which takes on argument called x
   (* x a))              ;return x times a

繰り返しますが、xは仮パラメーターです。しかし、どうaですか?afoo の本体で使用するとはどういう意味ですか? は 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.

于 2011-11-17T02:25:34.607 に答える
0

クロージャーは関数を実装するための ML (または Ocaml、Scheme、Lisp) の平均です。したがって、すべての関数はクロージャ (つまり、コードとデータの混合) です。例 (Ocaml 構文を使用)

 (* function making an incrementer, returning a function *)
 let make_incr i = fun x -> x + i;;

 (* use it to define the successor function *)
 let succ = make_incr 1;;

 (* compute the successor of 4 *)
 succ 4;;

もちろん、ocamlインタープリターは正常に応答しています

val make_incr : int -> int -> int = <fun>
val succ : int -> int = <fun>
 - : int = 5

make_incr が高階関数であることがわかります。整数を指定すると、新しい関数が生成されます。したがってsucc、上記の例では 1 が生成されます。加算コードとsucc整数 1 の両方が含まれています。そのため、コードとデータ (閉じた変数の環境) がクロージャ内に混在しています。

ウィキペディアのクロージャーに関するエントリ、および適切な教科書: SICP (Sussman による)、または C.Queinnec Lisp in Small Pieces、または Ocaml に関する優れた入門書、または Appel の本「Compiling with Continuations」などをお読みください。

于 2011-11-14T06:26:00.923 に答える