下面使用defunsetf定义的函数的基本区别是什么?一种方法比另一种方法更受欢迎吗?
使用defun

* (defun myfirst (l)
    (car l) )
MYFIRST

* (myfirst '(A B C))

A

使用setf
* (setf (fdefinition 'myfirst) #'(lambda (l) (car l)))

#<FUNCTION (LAMBDA (L)) {10021B477B}>
* (myfirst '(A B C))

A

如果,根据Wikipedia
命名函数是通过使用defun宏在符号中存储lambda表达式来创建的
使用setf以不同的方式创建变量需要使用funcall
* (defvar myfirst)

MYFIRST
* (setf myfirst (lambda (l) (car l)))

#<Interpreted Function (LAMBDA (X) (+ X X)) {48035001}>
* (funcall myfirst '(A B C))

A

我的理解是,这种类型的变量不同于前一种类型,因为在Why multiple namespaces?中描述的defun绑定符号所在的名称空间中找不到该变量。

最佳答案

首先,不要低估风格的重要性。
我们写代码不仅仅是为了让计算机运行,更重要的是,为了让人们阅读。
使代码可读和易于理解是软件开发的一个非常重要的方面。
其次,是的,(setf fdefinition)defun之间有很大的区别。
“小”的区别在于defun还可以设置函数名的doc string(实际上,取决于您的imeplementation的工作方式,它也可以对lambda进行设置),并创建一个命名的block(见下面的宏扩展),否则,如果您想创建自己,就必须创建一个命名的macroexpanding
最大的区别是编译器“知道”关于defun的内容,并将对其进行适当的处理。
例如,如果您的文件是

(defun foo (x)
  (+ (* x x) x 1))
(defun bar (x)
  (+ (foo 1 2 x) x))

然后编译器可能会警告您,您在foo中调用bar时使用了错误数量的参数:
警告:在第3..4行的bar中,foo是用3个参数调用的,但它需要1
争论。
[FOO在第1..2行中定义]
如果将defun foo替换为(setf (fdefinition 'foo) (lambda ...)),编译器就不太可能像这样小心地处理它而且,你可能会得到一个警告
使用但未定义以下函数:

您可能想通过defun检查defun在您的实现中的作用:
(macroexpand-1 '(defun foo (x) "doc" (print x)))

CLISP将其扩展到
(LET NIL (SYSTEM::REMOVE-OLD-DEFINITIONS 'FOO)
 (SYSTEM::EVAL-WHEN-COMPILE
  (SYSTEM::C-DEFUN 'FOO (SYSTEM::LAMBDA-LIST-TO-SIGNATURE '(X))))
 (SYSTEM::%PUTD 'FOO
  (FUNCTION FOO
   (LAMBDA (X) "doc" (DECLARE (SYSTEM::IN-DEFUN FOO)) (BLOCK FOO (PRINT X)))))
 (EVAL-WHEN (EVAL)
  (SYSTEM::%PUT 'FOO 'SYSTEM::DEFINITION
   (CONS '(DEFUN FOO (X) "doc" (PRINT X)) (THE-ENVIRONMENT))))
 'FOO)

SBCL:
(PROGN
 (EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'FOO NIL T))
 (SB-IMPL::%DEFUN 'FOO
                  (SB-INT:NAMED-LAMBDA FOO
                      (X)
                    "doc"
                    (BLOCK FOO (PRINT X)))
                  (SB-C:SOURCE-LOCATION)))

这里的重点是setf fdefinition有很多“隐藏”的东西,这是有原因的另一方面,更多的是“你看到的就是你得到的”,也就是说,不涉及魔法。
这并不意味着setf fdefinition在现代lisp代码库中没有位置您可以使用它,例如,实现“穷人的”(未经测试):
(defun trace (symbol)
  (setf (get symbol 'old-def) (fdefinition symbol)
        (fdefinition symbol)
        (lambda (&rest args)
          (print (cons symbol args))
          (apply (get symbol 'old-def) args))))
(defun untrace (symbol)
  (setf (fdefinition symbol) (get symbol 'old-def))
  (remprop symbol 'odd-def))

09-04 23:44