免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: xdshting
打印 上一主题 下一主题

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

论坛徽章:
0
1 [报告]
发表于 2009-03-09 00:04 |显示全部楼层
1. let 为 count 绑定了一个值 0,返回的匿名函数可以引用,修改它。这称为 static scope (lexical),类似于 c 语言中的静态变量。粗略地讲,闭包包住了一个私有环境。

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

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

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

论坛徽章:
0
2 [报告]
发表于 2009-03-09 00:18 |显示全部楼层
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 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2009-03-09 00:34 |显示全部楼层
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)的结果是一样的,但调用的是不同的函数。

论坛徽章:
0
4 [报告]
发表于 2009-03-09 01:05 |显示全部楼层
原帖由 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.


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

论坛徽章:
0
5 [报告]
发表于 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
6 [报告]
发表于 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
7 [报告]
发表于 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
8 [报告]
发表于 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
9 [报告]
发表于 2009-03-09 11:36 |显示全部楼层
就是全局吧。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP