为什么defun和(setq <name> <lambda>)不一样?

20

我对defun宏的工作原理感到困惑,因为:

(defun x () "hello")

将创建函数x,但符号x仍将未绑定。

如果我将一些lambda绑定到x上,则x将具有值,但解释器不会将其视为以下形式的函数:

(x)

我认为这与defun应该在全局环境中定义函数有关,但我不确定确切的意思是什么。为什么我不能在当前环境中阻止它?

是否有办法强制解释器将符号视为函数(如果某个lambda绑定到它)?例如:

(setq y (lambda () "I want to be a named function"))
(y)

顺便说一下:我正在使用SBCL。

2个回答

23

Common Lisp拥有不同的命名空间,用于函数和值。

你可以使用DEFUNFLETLABELS等函数在函数命名空间中定义函数。

如果你想要获取一个函数对象作为值,可以使用FUNCTION

(defun foo (x) (1+ x))

(function foo)   ->  #<the function foo>

或者更短:

#'foo    ->   #<the function foo>
如果你想调用一个函数,那么你需要写成 (foo 100) 的形式。
如果你想将函数作为值来调用,则需要使用FUNCALLAPPLY
(funcall #'foo 1)

您可以传递函数并调用它们:

(defun bar (f arg)
  (funcall f arg arg))

(bar #'+ 2)  ->  4
在DEFUN的情况下: 它不是 (setf (symbol-value 'FOO) (lambda ...))。 更像是(setf (symbol-function 'foo) (lambda ...))。 请注意,这两个命名空间允许您编写:
(defun foo (list)
  (list list))

(foo '(1 2 3))  ->  ((1 2 3))

内置函数LIST和变量LIST之间没有冲突。由于我们有两个不同的命名空间,因此我们可以为两个不同的目的使用相同的名称。

还要注意,在本地函数的情况下,不存在符号。 命名空间不一定与符号相关联。 因此,对于局部变量,无法通过符号名称进行函数查找。


7
Common Lisp每个符号都有多个槽,包括值槽和函数槽。当您使用语法(x)时,Common Lisp会查找x的函数槽绑定。如果您想调用值绑定,请使用funcallapply
请参见http://cl-cookbook.sourceforge.net/functions.html

1
真是太有趣了!我还以为 Perl 的 $foo、@foo、%foo、foo 很特别呢。 - Dmytro
1
在POSIX shell中,变量$testtest命令/函数无关。 - Kaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接