Lisp 匿名递归函数 v2:在 Common Lisp 中实现 Clojure 的 fn
2012-08-04 19:39
260 查看
我在之前的文章《Lisp 匿名递归函数》中提及 Emacs Lisp、Scheme 和 Common Lisp 中默认都没提供定义可递归的 lambda 函数的方法。并在文章里提供了我自己实现的 Emacs Lisp 版本和 Common Lisp 版本。
在那之后,我学习了 Clojure,发现 Clojure 中的 fn 在定义 lambda 函数的同时还允许给它取一个临时的名字,这样就能在函数体中递归地调用自己了,比如下面用来临时求第12个斐波那契数的匿名函数:
这个方法比我之前实现的要高明的多!我的方法会额外“霸占”一个名字“this”来代表自己,这样很容易有命名冲突的问题。但像 fn 这样,名字由开发者自己提供,就能避免这样的问题。因此,我开始琢磨怎么把 fn 迁移到 Common Lisp 中。
有了之前开发的经验,这一次实现起来顺手多了。观察 fn 的语法,与 lambda 相比它多了一个可选的名字。所以,当函数名未提供时和 lambda 无区别:
然后是 else 块,这部分和之前文章里介绍的一样,都是需要让返回的匿名函数能识别一个额外的函数名,并且那个函数名指向函数本身。区别仅是之前 hard code 成 this,而这回名字由开发者指定。所以,也是用“局部函数”来实现,即 Common Lisp 中的 labels,或 Emacs Lisp 中的 flet:
来写个函数测试一下。比如输出一棵树的所有子节点:
在 clisp 中执行结果如下:
在那之后,我学习了 Clojure,发现 Clojure 中的 fn 在定义 lambda 函数的同时还允许给它取一个临时的名字,这样就能在函数体中递归地调用自己了,比如下面用来临时求第12个斐波那契数的匿名函数:
((fn fibonacci (if (<= 2 n) (+ (fibonacci (- n 1)) (fibonacci (- n 2))) 1)) 12)
这个方法比我之前实现的要高明的多!我的方法会额外“霸占”一个名字“this”来代表自己,这样很容易有命名冲突的问题。但像 fn 这样,名字由开发者自己提供,就能避免这样的问题。因此,我开始琢磨怎么把 fn 迁移到 Common Lisp 中。
有了之前开发的经验,这一次实现起来顺手多了。观察 fn 的语法,与 lambda 相比它多了一个可选的名字。所以,当函数名未提供时和 lambda 无区别:
(defmacro fn (&rest body) (if (listp (car body)) `(lambda ,@body) ))
然后是 else 块,这部分和之前文章里介绍的一样,都是需要让返回的匿名函数能识别一个额外的函数名,并且那个函数名指向函数本身。区别仅是之前 hard code 成 this,而这回名字由开发者指定。所以,也是用“局部函数”来实现,即 Common Lisp 中的 labels,或 Emacs Lisp 中的 flet:
(defmacro fn (&rest body) (if (listp (car body)) `(lambda ,@body) `(lambda (&rest args) (labels (,body) (apply (function ,(car body)) args)))))
来写个函数测试一下。比如输出一棵树的所有子节点:
(funcall (fn dump-list (o) (if (consp o) (dolist (item o) (dump-list item)) (format t "~A~%" o))) '(1 (2 (3 (4) 5) 6) 7 (8 9)))
在 clisp 中执行结果如下:
λ clisp -q
[1]> (defmacro fn (&rest body) (if (listp (car body)) `(lambda ,@body) `(lambda (&rest args) (labels (,body) (apply (function ,(car body)) args)))))
FN
[2]> (funcall (fn dump-list (o) (if (consp o) (dolist (item o) (dump-list item)) (format t "~A~%" o))) '(1 (2 (3 (4) 5) 6) 7 (8 9)))
1
2
3
4
5
6
7
8
9
NIL
[3]>
相关文章推荐
- Lisp 匿名递归函数
- Lisp: Common Lisp, Racket, Clojure, Emacs Lisp - Hyperpolyglot
- 揽货最短路径解决方案算法 - V2(增加了时间维度-客户允许的服务时间段,C#/JAVA同步实现,带python作图)
- 递归函数的练习,汉诺塔问题的程序实现(递归)
- 通过匿名管道实现进程间通信
- Clojure:在REPL上实现一个简单的shell(二)
- 进程间通信 - 匿名管道实现
- CentOS7搭建ftp服务器实现匿名上传下载
- 基于visual c++之windows核心编程代码分析(51)基于匿名管道实现远程控制
- 判断回文串的递归函数实现(c++)
- MvpHelper-v2 一键生成接口与实现类
- python实现斐波那契递归函数的方法
- 进程间通信 - 匿名管道实现
- SQL2008报表三种实现Reporting Service2008匿名访问的方法(转)
- Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
- 用递归函数实现输出一个数的二进制形式
- main方法中编写匿名内部类实现空字符串的去除
- zen cart实现匿名评论功能
- 匿名内部类是否可以继承其他类或实现接口
- 搭建FTP服务,实现三种方式的访问:1.匿名访问;2,本地用户访问;3虚拟用户访问。