能不能讲一下closure,正在看practical common lisp,就是理解不了这个概念

发布于 2022-08-12 18:36:15 字数 1611 浏览 10 评论 9

书上的例子是
(let ((count 0)) #'(lambda () (setf count (1+ count))))

the reference to count inside the LAMBDA form should be legal according to the rules of lexical scoping. Yet the anonymous function containing the reference will be returned as the value of the LET form and can be invoked, via FUNCALL, by code that’s not in the scope of the LET. So what happens? As it turns out, when count is a lexical variable, it just works. The binding of count created when the flow of control entered the LET form will stick around for as long as needed, in this case for as long as someone holds onto a reference to the function object returned by the LET form. The anonymous function is called a closure because it “closes over” the binding created by the LET.
The key thing to understand about closures is that it’s the binding, not the value of the variable, that’s captured. Thus, a closure can not only access the value of the variables it closes over but can also assign new values that will persist between calls to the closure. For instance, you can capture the closure created by the previous expression in a global variable like this:

(defparameter *fn* (let ((count 0)) #'(lambda () (setf count (1+ count)))))

Then each time you invoke it, the value of count will increase by one.

CL-USER> (funcall *fn*)
1
CL-USER> (funcall *fn*)
2
CL-USER> (funcall *fn*)
3
基本上没看明白,而且红色的地方也有点奇怪

[ 本帖最后由 xdshting 于 2009-3-8 23:44 编辑 ]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

卖梦商人 2022-08-21 07:49:04

原帖由 flw 于 2009-3-9 09:06 发表
1+ 是个函数名称呢?
还是仅仅只是 + 这个函数 curry 化的结果?

lisp 不支持自动 curry 化,1+ 是专门另做的一个函数。当然本质上可以看成 1+x 的 curry

在 emacs 中,对 1+ 的描述为:

1+ is a built-in function in `C source code'.

(1+ NUMBER)

Return NUMBER plus one.  NUMBER may be a number or a marker.
Markers are converted to integers.

财迷小姐 2022-08-21 07:47:24

谢谢了
再看ansi common lisp关于closure的介绍,又有一点不明白的地方
书上的例子
( let ((counter 0))
    (defun reset ()
       (setf counter 0))
    (defun stamp ()
       (setf counter (+ counter 1))))

CL-USER> ( l i s t (stamp) (stamp) ( reset ) (stamp))
          ( 1 2 0 1)

list是怎么看到stamp和reset函数的?这两个函数在let内部定义的阿

[ 本帖最后由 xdshting 于 2009-3-9 09:38 编辑 ]

超可爱的懒熊 2022-08-21 05:53:41

1+ 是个函数名称呢?
还是仅仅只是 + 这个函数 curry 化的结果?

樱花坊 2022-08-21 04:44:42

原帖由 xdshting 于 2009-3-9 00:50 发表
谢谢,现在明白一些了

看到您用
(funcall '+ 3 4)
我用
(funcall #'+ 3 4)

可以得到相同的结果,我觉得你用的形式不对阿,为什么能执行?

参考这个连接,http://www.lispworks.com/documen ... c/Body/f_funcal.htm

Syntax:

funcall function &rest args => result*

......

funcall applies function to args. If function is a symbol, it is coerced to a function as if by finding its functional value in the global environment.

所以两种形式都是可以的。

兰花执着 2022-08-21 04:23:36

谢谢,现在明白一些了

看到您用
(funcall '+ 3 4)
我用
(funcall #'+ 3 4)

可以得到相同的结果,我觉得你用的形式不对阿,为什么能执行?

情泪▽动烟 2022-08-20 16:33:31

1、

  1. 每次运行(funcall (let ((count 0)) #'(lambda () (setf count (1+ count))))) 的值都是1

复制代码
因为每次运行都得到一个新的匿名函数,它也包有一个新的环境,在该环境中,count 值为 0。

2、

  1. (defparameter *fn* (let ((count 0)) #'(lambda () (setf count (1+ count)))))

复制代码
以后通过 *fn* 去调用,let 只执行了一次,只有一个与 *fn* 关联的匿名函数(相应的私有空间)。

看看下面的演示

  1. [1]> (defparameter f (let ((count 0)) #'(lambda () (setf count (1+ count)))))F
  2. [2]> (defparameter g (let ((count 0)) #'(lambda () (setf count (1+ count)))))
  3. G
  4. [3]> (funcall f)
  5. 1
  6. [4]> (funcall f)
  7. 2
  8. [5]> (funcall f)
  9. 3
  10. [6]> (funcall g)
  11. 1
  12. [7]>

复制代码

f, g 的私有空间是不同的。直接 funcall let 的结果相当于每次都生成一个新函数,所以值也都是 1 了。

3、1+ 是个函数名字,这个函数接受一个参数;+ 是另外一个函数,接受 0 个或多个参数.

  1. > (funcall '1+ 2)
  2. 3
  3. > (funcall '+ 1 2)
  4. 3
  5. > (funcall '+ 2 1)
  6. 3

复制代码

(1+ count)与(+ 1 count)的结果是一样的,但调用的是不同的函数。

隐诗 2022-08-19 09:30:22

每次运行(funcall (let ((count 0)) #'(lambda () (setf count (1+ count))))) 的值都是1

(defparameter *fn* (let ((count 0)) #'(lambda () (setf count (1+ count)))))

Then each time you invoke it, the value of count will increase by one.

CL-USER> (funcall *fn*)
1
CL-USER> (funcall *fn*)
2
CL-USER> (funcall *fn*)
3
这怎么解释,红色部分不就是说用defparameter代替后面的(let...)吗?
另外
(1+ count)与(+ 1 count)有区别吗?

谢谢

[ 本帖最后由 xdshting 于 2009-3-9 00:23 编辑 ]

双手揣兜 2022-08-17 07:39:07

scheme 是第一个引入静态作用域的 lisp,后来 Guy Steel 跑去开发 common lisp,把这个也加进去了。

有一些 lisp 是动态作用域的,比如 elisp. 如果在 emacs 中执行

  1. (setq *fn* (let ((count 0)) #'(lambda () (setq count (1+ count)))))
  2. (funcall *fn*)

复制代码

就会出错,因为: Debugger entered--Lisp error: (void-variable count)

显然 *fn* 找不到 count 了。如果在函数外面定义一个 count,值为 100

  1. (setq *fn* (let ((count 0)) #'(lambda () (setq count (1+ count)))))
  2. (setq count 100)
  3. (funcall *fn*)

复制代码

则 funcall 的结果为 101,显然跟 let 里头的 count 是无关的。

[ 本帖最后由 win_hate 于 2009-3-9 00:19 编辑 ]

动次打次papapa 2022-08-15 07:23:50

1. let 为 count 绑定了一个值 0,返回的匿名函数可以引用,修改它。这称为 static scope (lexical),类似于 c 语言中的静态变量。粗略地讲,闭包包住了一个私有环境。

2. 返回的匿名函数若与变量 *fn* 绑定,则可以通过 *fn* 来调用,访问并修改匿名函数的“私有环境”。

3. lisp 支持自动垃圾回收,当匿名函数不再被使用时,资源会被回收。(... will stick around for as long as needed ...)

4. 1+ 是个函数,对参数执行加 1 操作.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文