我正在上一门使用 ML 的课程,我们正在讨论闭包,但我不太了解它们,尤其是在 ML 中。我在课堂上记笔记,它们对我没有多大意义/提供足够的细节。我尝试在网上四处寻找更多信息,但找不到任何信息。
有谁知道任何关于 ML 中的闭包(或关于 ML / 闭包)非常好的资源?
或者,如果有人可以就如何在 ML 中实现闭包或 ML 中的闭包是什么样子、闭包是什么等发表一些一般性的想法/解释,我将非常感激。我只是想了解闭包的概念/使用。
提前致谢!
我不知道任何 ML,所以我的答案将是 Scheme,它是另一种函数式编程语言。我假设您不了解 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 的主体中使用时,我们的意思是什么?a
没有在 foo 中定义,所以它被称为自由变量。要了解是什么a
意思,我们必须查看 foo 外部。例如,假设 foo 在此上下文中定义:
(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)是词法范围的,这意味着要找出变量的a
含义,我们需要查看文本上下文(希望这是有道理的)。
现在,上面的定义bar
实际上是不正确的:即使思想会foo
返回一些东西,bar
也不会返回任何东西。它定义foo
为内部函数,但是在该定义之后没有语句。让我们解决这个问题:
(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
现在,bar
返回函数foo
。我们刚刚变成bar
了一个高阶函数,因为它返回另一个函数。
但是有一个问题。通常,当返回时,不再需要bar
局部变量,并且它的值会丢失。a
但foo
仍然参考a
!所以a
需要再坚持一段时间。这就是闭包的用武之地。 的值a
是“封闭的”,所以只要函数存在,它就会一直foo
存在。这样,我们foo
甚至可以bar
在执行完成后调用。现在,让我们重命名foo
并bar
看看为什么这很有用:
(define (make-multiplier a)
(define (multiplier x)
(* x a))
multiplier)
现在,我们可以这样做:
(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.
所以 - 当一个函数有一个“自由变量”时,会为函数创建一个闭包,它“关闭”自由变量并在函数的生命周期内保留它。这样,当函数被传递并离开它定义的上下文时,“自由变量”继续有效。
闭包是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 是一个高阶函数:给定一些整数,它会产生一个新函数。所以给定 1 它succ
在上面的例子中产生。并且succ
包含加法代码和整数 1。因此它将代码和数据(封闭变量的环境)混合在一个闭包中。
阅读更多 Wikipedia 关于closure的条目,以及任何好的教科书:SICP(Sussman 撰写)或 C.Queinnec Lisp in Small Pieces,或任何关于 Ocaml 的好的介绍性书籍,或 Appel 的书“Compiling with Continuations”等。