在 Common Lisp 中定义和使用变量中的函数

Fra*_*ank 5 lambda scheme common-lisp

我偶然发现了这个文章,解释在Y Combinator的。代码在 Scheme 中,但我正在尝试使用 Common Lisp 来解决它。

但是,我在将 Scheme 转换为 Common Lisp 时遇到了麻烦。Scheme 为函数和(其他)变量使用单一命名空间,但 Common Lisp 为函数和变量使用不同的命名空间。我怎样才能解决这个差异,以获得工作的 Common Lisp 代码?

方案代码

这是教程中的一些 Scheme 代码。

一开始作者定义了阶乘函数:

(define (factorial n)
  if (= n 0)
    1
    (* n (factorial (- n 1)))))
Run Code Online (Sandbox Code Playgroud)

并将其翻译成这样:

(define factorial
  (lambda (n)
    (if (= n 0)
      1
      (* n (factorial (- n 1))))))
Run Code Online (Sandbox Code Playgroud)

因为(根据作者的说法)这就是 Scheme 所做的:

Scheme 在评估它之前简单地将第一个定义转换为第二个定义。所以 Scheme 中的所有函数都是真正的 lambda 表达式。

通用 Lisp

我尝试在 Common Lisp 中重写上述两个片段,以模仿从第一种形式到第二种形式的转换。但是defineCL 中没有,也没有单个名称空间。所以我试图欺骗我的方式。

在 Common Lisp 中重写第一个 Scheme 定义很容易:

(defun factorial (n)
    (if (= n 0)
        1
        (* n (factorial (- n 1)))))
Run Code Online (Sandbox Code Playgroud)

但是(对我而言)将其转换为第二个定义有点棘手。我是这样翻译的:

(setf (symbol-function 'factorial)
  (lambda (n)
    (if (= n 0)
      1
      (* n (factorial (- n 1))))))
Run Code Online (Sandbox Code Playgroud)

这是一种不好的方法吗(或者有更好的方法)?它似乎有效,但编译器给了我一个样式警告:未定义的函数:阶乘。

Rai*_*wig 3

在某些方面它更像是这样的:

(setf (symbol-function 'factorial)
      (labels ((factorial (n)
                 (if (= n 0)
                     1
                   (* n (factorial (- n 1))))))
        #'factorial))
Run Code Online (Sandbox Code Playgroud)

LABELS定义局部函数factorial。在本地函数的定义内,factorial任何调用都是factorial对该函数的调用。然后我们从标签表达式返回这个函数。因此,您可以定义递归函数,其中递归调用不是对未定义的函数。

如果您查看 Common Lisp 实现,您会发现 DEFUN 通常会扩展为不可移植的结构,例如命名 lambda 函数。此外,DEFUN 还具有编译时副作用。