我有以下 lisp 代码
(defun sum (vec)
"Summiert alle Elemente eines Vektors."
(apply '+ vec))
(defun square (item)
"Hilfsfunktion zum Quadrieren eines Elements."
(* item item))
(defun calcVarianz (vec)
"Berechnet die Varianz eines Vektors."
(loop with len = (length vec)
with mean = (/ (sum vec) len)
with some_func = (lambda (x) (* x x))
; causes the error
for item in vec
collecting (square (- item mean)) into squared
collecting (some_func item) into some_vector
; some_func cannot be found
finally (return (/ (sum squared) (- len 1)))))
Run Code Online (Sandbox Code Playgroud)
效果很好(即计算向量的方差)。
现在,我想知道是否可以在构造中将sum和square函数定义为 lambda loop,但一路上陷入困境。这可以用例如
with sum = (lambda (x) ...)
Run Code Online (Sandbox Code Playgroud)
出现错误
The function COMMON-LISP-USER::SOME_FUNC is undefined.
[Condition of type UNDEFINED-FUNCTION]
Run Code Online (Sandbox Code Playgroud)
我在这里缺少什么?
如果将符号绑定到需要使用的函数funcall或apply尝试使用符号调用函数时:
collecting (funcall some_func item) into some_vector
Run Code Online (Sandbox Code Playgroud)
这是因为通常在绑定符号时会绑定值槽,而在这种情况下,值槽会与函数的值绑定。当遇到一个符号作为 cons 的第一个元素时,将检查函数槽是否有该函数,这是一个不同的命名空间。这就是需要funcall(或) 的原因。apply
您可以调用funcall全局环境中的函数对象或符号。如果一个符号被传递给funcall它,它就会被强制传递给一个函数;该符号必须位于全局环境中以避免未定义的行为。
在这种特殊情况下,局部变量some_func绑定到lambda表达式指定的函数对象。由于funcall它本身是一个函数,因此它计算其参数,因此some_func计算其值,即一个函数对象。然后将该函数对象funcall与 的值一起传递给item.
将此与 OP 代码进行对比(some_func item)。通过首先尝试查找 的全局函数绑定来评估此形式,但由于是局部变量,some_func因此找不到任何绑定。some_func因此会发出错误:
The function COMMON-LISP-USER::SOME_FUNC is undefined.
[Condition of type UNDEFINED-FUNCTION]
Run Code Online (Sandbox Code Playgroud)