免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 9091 | 回复: 16
打印 上一主题 下一主题

能不能讲一下closure,正在看practical common lisp,就是理解不了这个概念 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-03-08 23:39 |只看该作者 |正序浏览
书上的例子是
(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 编辑 ]

论坛徽章:
0
17 [报告]
发表于 2009-05-21 20:45 |只看该作者
原帖由 xdshting 于 2009-3-8 23:39 发表
书上的例子是
(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 anonymou ...



C语言只能返回函数指针,所以函数指针只是函数指针。

但Closure就是将函数指针与上下文的变量绑定在一起了;所以返回的函数指针就不再一样。


根据count的值的不同,返回的函数指针(lambda函数)与count形成的闭包,就形成了各种不同的函数(部分变量已经绑定不同值)。

(...
    (lambda (x)
        (+ n x))

根据n的不同值,返回的lambda函数就是 x+1, 或x+2,或x+3函数(变量n已经绑定)。

论坛徽章:
0
16 [报告]
发表于 2009-03-09 11:36 |只看该作者
就是全局吧。

论坛徽章:
0
15 [报告]
发表于 2009-03-09 11:27 |只看该作者
原帖由 win_hate 于 2009-3-9 11:12 发表
我查了一个:

http://community.schemewiki.org/?scheme-faq-language

scheme 的 faq,在里面的 Is there a way to define top-level closures?  一节说到:



所以你能在 let 外访问 let 中定义的函 ...


在很多地方都看到top-level这个词,您能不能详细解释以下

给我的感觉有一点像是全局的意思

论坛徽章:
0
14 [报告]
发表于 2009-03-09 11:22 |只看该作者
原帖由 xdshting 于 2009-3-9 11:05 发表
>>1,看了一些对closure的介绍

有一个感觉,有点像java里的封装吗,把free variable看作私有变量,只有通过对外接口去访问他

这样理解对不对?



2,另外,还是有点不明白,什么时候变量可以递增,什么时候 ...


1、不懂 java,不过 “把free variable看作私有变量” 是对的。

2、就好比,如果你多次执行 (+ 1 1),则每次都会计算一个加法。
但 (setq a (+ 1 1)) 后,每次执行 a,都直接得到 2,不会再执行一次加法。

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


求值方式为:

a. 求出 (let ((count 0)) #'(lambda () (setf count (1+ count))) 的值。此时创建了匿名函数;
b. 把匿名函数入口绑定到 *fn* 上。

以后再执行 *fn* 时,就直接访问匿名函数了。

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

论坛徽章:
0
13 [报告]
发表于 2009-03-09 11:12 |只看该作者
我查了一个:

http://community.schemewiki.org/?scheme-faq-language

scheme 的 faq,在里面的 Is there a way to define top-level closures?  一节说到:

In Common Lisp, the defun construct always creates a top-level definition, e.g.


所以你能在 let 外访问 let 中定义的函数。

而在 scheme 中, let 通常是个 sugar,被转换成 curry 函数。所以在 let 的外部就不能直接访问 let  内部定义的函数了(除非把它作为 let 的最后一项返回)。

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

论坛徽章:
0
12 [报告]
发表于 2009-03-09 11:05 |只看该作者
1,看了一些对closure的介绍

有一个感觉,有点像java里的封装吗,把free variable看作私有变量,只有通过对外接口去访问他

这样理解对不对?

2,另外,还是有点不明白,什么时候变量可以递增,什么时候他被重新初始化

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

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

为什么只调用一次,是defparameter捣鬼吗?

论坛徽章:
0
11 [报告]
发表于 2009-03-09 10:51 |只看该作者
原帖由 xdshting 于 2009-3-9 09:22 发表
谢谢了
再看ansi common lisp关于closure的介绍,又有一点不明白的地方
书上的例子
( let ((counter 0))
    (defun reset ()
       (setf counter 0))
    (defun stamp ()
       (setf counter (+ c ...


问得好。在 scheme 中,这样是不行的。如果你不说,我还真不知道 common lisp 有这一手。

我对 common lisp 不了解,还是等对 common lisp 比较熟悉的朋友来回答吧。

论坛徽章:
0
10 [报告]
发表于 2009-03-09 10:46 |只看该作者
原帖由 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.

论坛徽章:
0
9 [报告]
发表于 2009-03-09 09:22 |只看该作者
谢谢了
再看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 编辑 ]
  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP