在循环中从用“with”定义的变量调用 lambda 函数

Jan*_*Jan 1 lisp common-lisp

我有以下 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)

效果很好(即计算向量的方差)。
现在,我想知道是否可以在构造中将sumsquare函数定义为 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)

我在这里缺少什么?

ex *_*ilo 5

如果将符号绑定到需要使用的函数funcallapply尝试使用符号调用函数时:

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)

  • 很好的解释,谢谢。 (2认同)