使用defun或setf首选在通用Lisp中创建函数定义吗?为什么? [英] Is defun or setf preferred for creating function definitions in common lisp and why?

查看:138
本文介绍了使用defun或setf首选在通用Lisp中创建函数定义吗?为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下使用defunsetf定义的函数的基本区别是什么?除了样式考虑之外,一种方法优先于另一种方法吗?

What is the fundamental difference in the functions defined using defun and setf as below and is one method preferred over another outside of style considerations?

使用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

如果根据维基百科:

使用defun宏通过将lambda表达式存储在符号中来创建命名函数

named functions are created by storing a lambda expression in a symbol using the defun macro

使用setf以其他方式创建变量需要使用funcall:

Using setf to create a variable in a different way requires the use of funcall:

* (defvar myfirst)

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

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

A

我的理解是,这种类型的变量与以前的变量不同,因为在

My understanding is that this type of variable is different than the previous in that this variable is not found in the same namespace as the defun bound symbol as described in Why multiple namespaces?.

推荐答案

首先,永远不要低估样式的重要性. 我们不仅为计算机运行编写代码,而且更重要的是,供人们阅读. 使代码对人们可读和理解是软件开发的一个非常重要的方面.

First of all, one should never underestimate the importance of style. We write code not just for computers to run, but, much more importantly, for people to read. Making code readable and understandable for people is a very important aspect of software development.

第二,是的, (setf fdefinition) defun .

Second, yes, there is a big difference between (setf fdefinition) and defun.

小的"区别在于defun还可以设置文档字符串函数名称的名称(实际上,取决于实现的方式,也可以使用lambda来实现),并创建一个名为 block (在下面的宏扩展中看到),否则,如果需要,您必须创建自己.

The "small" differences are that defun can also set the doc string of the function name (actually, depending on how your imeplementation works, it might do that with lambda also), and creates a named block (seen in the macroexpansions below) which you would otherwise have to create yourself if you want to.

最大的区别在于,编译器了解" defun,并将对其进行适当的处​​理.

The big difference is that the compiler "knows" about defun and will process it appropriately.

例如,如果您的文件是

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

然后编译器可能会警告您,您在bar中调用foo时使用了错误的参数数量:

then the compiler will probably warn you that you call foo in bar with the wrong number of arguments:

警告:在BAR的第3..4行中:FOO带有3个参数,但需要1个参数 争论. [FOO在1..2行中定义]

WARNING: in BAR in lines 3..4 : FOO was called with 3 arguments, but it requires 1 argument. [FOO was defined in lines 1..2 ]

如果将defun foo替换为(setf (fdefinition 'foo) (lambda ...)),则编译器不太可能谨慎处理它.此外,您可能会得到类似

If you replace the defun foo with (setf (fdefinition 'foo) (lambda ...)), the compiler is unlikely to handle it as carefully. Moreover, you will probably get a warning along the lines of

已使用但未定义以下功能: FOO

The following functions were used but not defined: FOO

您可能想通过宏扩展来检查defun在实现中的作用:

You might want to examine what defun does in your implementation by macroexpanding it:

(macroexpand-1 '(defun foo (x) "doc" (print x)))

CLISP将其扩展到

CLISP expands it to

(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)))

这里的要点是defun具有很多内幕",这是有原因的.另一方面,setf fdefinition更多的是所见即所得",即不涉及任何魔术.

The point here is that defun has a lot "under the hood", and for a reason. setf fdefinition is, on the other hand, more of "what you see is what you get", i.e., no magic involved.

这并不意味着setf fdefinition在现代的Lisp代码库中没有位置.您可以使用它来实现穷人的 trace "(未测试):

This does not mean that setf fdefinition has no place in a modern lisp codebase. You can use it, e.g., to implement a "poor man's trace" (UNTESTED):

(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))

这篇关于使用defun或setf首选在通用Lisp中创建函数定义吗?为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆