研究下Scheme和Lisp在lamba上的区别。今天晚上特别郁闷。本来想体会一下Lisp中函数作为第一等变量等柑橘,想不到却不知道载了多少个跟头。
Scheme
Scheme作为Lisp的一个方言,由MIT研发,并且GPL的协议下发布。大家可以从GNU官网上下载其源码,然后编译安装。Scheme相对与Lisp结合了Agol(不确定)。我们现在来看一下载Scheme语言中如何返回一个函数:
(define (repeat-2 fun)
(lambda (x) (fun (fun x)))
上述定义的函数将函数fun的功能重复两遍。其使用方法如下,假设定义了加1函数incf,
((repeat-2 incf) 1)
这样就将incf重复了两次。
Lisp
如果对Scheme的使用方式比较熟悉,那么在使用lisp实现时会觉得很奇怪。因为Lisp解析器根据变量的位置不同来决定变量是函数还是变量。Lisp中由两个函数boundp和fboundp,分别判断一个名字是否时一个有值的变量或者函数。载Lisp中lambda是宏,其展开时会调用function。举个例子。
(defun repeat-2 (fun)
(lambda (x) (funcall fun (funcall fun x))))
此时解析器会将其展开成如下:
(defun repeat-2 (fun)
(function lambda (x) (funcall fun (funcall fun x))))
Lisp允许我们只写lambda只是提供了一个语法糖,允许我们直接使用。注意到将函数作为变量值传递给函数时,调用方式不能像Scheme那样直接调用,而是需要funcall或者apply来调用。repeat-2返回将指定的函数重复2次的功能,返回的函数值,我们不能直接使用,也必须使用funcall或者apply。相对于Scheme好像有点复杂。
(funcall (repeat-2 #'incf) 1)
今晚在测试的时候使用Lisp系统自带的incf,结果报错,说incf是宏,不是函数。当时没注意,以为是调用方式出问题,便加了#'。后来又报错说值不能放函数定义。后来回过头来想起,原来incf是,他们封装了set的功能。于是自己写了incf-my,然后按照上面的方式执行一遍,结果OK。
后来Google搜索了相关的使用方法。原来Lisp中有两个Cell,姑且成为function cell和alue cell。所以允许函数名字和变量名字相同,解析器是根据位置来确定到底时解析成函数还是变量。通过之前说的boundp和fboundp来判断到底是变量还是函数。
本文完。