如何在 Common Lisp 中设置函数

How to set a function in Common Lisp

在 Common Lisp 中,我可以使用 #' 语法获取一个函数来传递,如下所示:

(let ((x #'+))
 (funcall x 1 2))

但是假设我想设置一个函数,这样我就不必为它使用 funcall。 Common Lisp 是否有一个局部函数名称 table,或者只是分配给 defun 的全局函数名称?

有没有办法分配给 defun 以外的函数符号?或者更一般地说:有没有一种方法可以做类似于这个无效示例的事情:

(setf #'x #'+)
(x 1 2)

您可以使用 flet and labels:

(flet ((f (x) (1+ (* 2 x))))
  (f 7))
==> 15

您还可以使用 fdefinition:

设置交易品种的函数定义
(setf (fdefinition 'f) #'+)
(f 1 2 3)
==> 6

请注意 let 绑定 value cell of the symbol while flet bind the function cell。 当符号出现在 "function" 位置时, "function" 使用单元格,而当它出现在 "value" 位置时, "value" 使用的单元格:

(setf (symbol-function 'x) #'car)
(setf (symbol-value 'x) #'cdr)
(x '(1 . 2))
==> 1
(funcall x '(1 . 2))
==> 2

同样,

(flet ((x (o) (car o)))
  (let ((x #'cdr))
    (cons (x '(1 . 2))
          (funcall x '(1 . 2)))))
==> (1 . 2)

这是difference between Lisp-1 and Lisp-2

最后,请注意CLISP is just one implementation of the language ANSI Common Lisp

获得这种行为的一种选择是编写一个宏来实现它。

(defmacro flet* (assignments &body body)
  (let ((assignments (mapcar
                      (lambda (assn)
                        (list (first assn) '(&rest args)
                              (list 'apply (second assn) 'args)))
                      assignments)))
    `(flet ,assignments ,@body)))

这个宏将 flet* 翻译成 flet + apply 像这样:

(flet* ((x #'+)
        (y #'*))
       (pprint (x 1 2))
       (pprint (y 3 4))
       (pprint (x (y 2 3) 4)))

变成:

(flet ((x (&rest args) (apply #'+ args))
       (y (&rest args) (apply #'* args)))
       (pprint (x 1 2))
       (pprint (y 3 4))
       (pprint (x (y 2 3) 4)))