我偶然发现了解释Y Combinator的this文章。代码在Scheme中,但我正在尝试使用Common Lisp。
但是,我在从Scheme到Common Lisp的翻译时遇到了麻烦。 Scheme对函数和(其他)变量使用单个命名空间,但Common Lisp对函数和变量使用不同的命名空间。如何解决这个差异,以获得有效的Common Lisp代码?
这是教程中的一些Scheme代码。
在开始时,作者定义了阶乘函数:
(define (factorial n)
if (= n 0)
1
(* n (factorial (- n 1)))))
并将其翻译成:
(define factorial
(lambda (n)
(if (= n 0)
1
(* n (factorial (- n 1))))))
因为(根据作者的说法)这就是Scheme所做的事情:
Scheme简单地将第一个定义转换为第二个定义 在评估它之前。所以Scheme中的所有函数都是lambda 表达式。
我试图重写Common Lisp中的上述片段,以模仿从第一种形式到第二种形式的过渡。但是CL中没有define
,也没有一个名称空间。所以我试图欺骗它。
重写Common Lisp中的第一个Scheme定义很简单:
(defun factorial (n)
(if (= n 0)
1
(* n (factorial (- n 1)))))
但是(对我而言)将其翻译成第二个定义有点棘手。我翻译成这样:
(setf (symbol-function 'factorial)
(lambda (n)
(if (= n 0)
1
(* n (factorial (- n 1))))))
这是一个不好的方法吗(或者有更好的方法)?它似乎工作,但编译器给我一个样式警告:未定义的函数:factorial。
答案 0 :(得分:3)
在某些方面,它更像是这样:
(setf (symbol-function 'factorial)
(labels ((factorial (n)
(if (= n 0)
1
(* n (factorial (- n 1))))))
#'factorial))
LABELS
定义了本地函数factorial
。在本地函数factorial
的定义中,对factorial
的任何调用都是针对该函数的。然后我们从labels表达式返回此函数。因此,您可以定义递归函数,其中递归调用不是未定义的函数。
如果你看一下Common Lisp实现,你可以看到DEFUN经常扩展为非可移植的构造,比如名为lambda的函数。此外,DEFUN还具有编译时副作用。
答案 1 :(得分:2)
公共列表中的转换毫无意义。
CL defun
通常不仅仅是(setf fdefinition)
。
您可以通过评估(macroexpand-1 '(defun foo (a b c) (bar c a b)))
。
真正的问题是 - 你为什么要这样做?
答案 2 :(得分:2)
如果我理解正确,你问题的主旨就是在"Lisp-1" and a "Lisp-2"之间进行翻译。
Scheme是一个“Lisp-1” - 它为函数和变量都有一个命名空间。另一方面,Common Lisp是一个“Lisp-2” - 它有函数和变量的独立命名空间。
在方案中,你可以写
(define foo (lambda (...) ...))
然后调用foo
,如:
(foo ...)
我们也可以在Common Lisp中以完全相同的方式定义foo
,但如果我们尝试使用该语法调用 foo
,您的程序将崩溃。这是因为foo
位于变量名称空间中,而不是 function 名称空间。
我们可以使用funcall
来调用foo
:
(funcall foo ...)
这是一个简短的介绍。 Common Lisp Cookbook上的Functions页面提供了您可能会觉得有用的其他详细信息。