为什么我们必须使用
funcall
来调用 Common Lisp 中的高阶函数?例如,为什么我们必须使用:
(defun foo (test-func args)
(funcall test-func args))
而不是更简单的:
(defun bar (test-func args)
(test-func args))
来自程序背景的我对此感到有点惊讶,因为我更习惯的语言(例如 Python、C#)不需要区分。特别是,至少在源代码级别,C# 编译器将其转换为类似
func.invoke()
的内容。
我看到的唯一问题是,这意味着我们无法再调用全局函数
test-func
,因为它会被隐藏,但这几乎不是问题。
大多数 Lisp 都有两个命名空间(函数和变量)。当名称作为 S 表达式中的第一个元素出现时,将在函数命名空间中查找,否则将在变量命名空间中查找。这允许您命名变量而不必担心它们是否隐藏函数:因此您可以将变量命名为
list
,而不必将其弄乱为lst
。
但是,这意味着当你将函数存储在变量中时,你无法正常调用它:
(setq list #'+) ; updates list in the variable namespace
(list 1 2 3) => (1 2 3) ; looks up list in the function namespace
funcall
和 apply
:
(funcall list 1 2 3) => 6 ; looks up list in the variable namespace
(并非所有 Lisp 都有两个命名空间:Scheme 是仅具有一个命名空间的 Lisp 的一个示例。)
在 Common Lisp 中,每个符号都可以与其“符号函数”和“符号值”等相关联。读取列表时,默认情况下,Common Lisp 会解释:
arg1 作为一个函数,因此检索 test-func
symbol-function
bar
不起作用arg2 作为要 eval
ed 的东西 - 因此函数 foo
test-func
的 symbol-value
,在你的情况下,它恰好是一个函数