将lambda绑定到函数或var是否在语义上更正确?

时间:2015-04-03 14:50:56

标签: lambda common-lisp

我正在编写一个将名称绑定到返回lambda的表达式的简单宏,但由于常见的lisp具有不同的函数和值的名称空间,我需要funcall它无论我是将其包裹在defun还是defvar中。

(defun foo () (lambda-returning-expr)) 
(defvar bar (lambda-returning-expr)) 

(funcall (foo)) ; evaluates correctly 
(funcall bar) ; also evaluates 

那么哪种方法更正确?或者更确切地说,哪个最受索撒者的青睐?

2 个答案:

答案 0 :(得分:4)

(defun foo () (lambda-returning-expr)) 
(defvar bar (lambda-returning-expr)) 

两种情况都需要 funcall ,例如(funcall(foo))(funcall bar),但是有一个(foo)涉及额外的函数调用,每次都会评估(lambda-returning-expr),因此你可以得到一个不同的每次都回来。

  • 如果您希望可能有不同的功能,那么使用 foo 等功能将是合适的。
  • 如果你只想要一个,那么变量就像 bar 一样合适。
  • 如果您希望用户想要更改功能(例如,使用(let((bar ...))...)作为API的一部分,然后一个变量肯定有意义。这在标准中使用,例如,用于*macroexpand-hook*。如果你需要这样做,那么特殊变量几乎肯定是要走的路,因为Common Lisp没有动态范围函数。

最近有一个类似的方案问题Differences between two similar definitions,其中讨论了其中一些问题。

答案 1 :(得分:2)

(funcall (foo))不是老虎钳的选择,因为你做了两个函数调用而不是一个。如果你想创建一个全局函数,你可以使用它:

(setf (symbol-function 'foo) (lambda (x) x))
(foo 10) ; ==> 10

您也可以使用变量,但请记住defvar仅确保变量绑定。

(defvar *test* 10)
*test* ; ==> 10
(defvar *test* (lambda (x) x))
*test* ; ==> 10 (not changed since it's already existing)

如果您希望始终将其设置为已评估的表达式,请使用defparameter

(defparameter *test* 10)
*test* ; ==> 10
(defparameter *test* (lambda (x) x))
*test* ; ==> #<FUNCTION :LAMBDA (X) X>

BTW:defvardefparameter会产生特殊变量。请记住*earmuffs*,这样您就不会因为动态范围而陷入奇怪的错误。