普通 Lisp,"defined but never used"

Common Lisp, "defined but never used"

This function compile with warnings, fn is defined and never used in the first line, fn 是未定义的函数第二行:

(defun test-function (fn)
  (funcall #'fn))

为什么?对它进行一般性解释或 link 会很棒。

PD:完整日志:

test.lisp:9:1:                                                                             
  style-warning:                                                                           
    The variable FN is defined but never used.                                             
    --> PROGN SB-IMPL::%DEFUN SB-IMPL::%DEFUN SB-INT:NAMED-LAMBDA                          
    ==>                                                                                    
      #'(SB-INT:NAMED-LAMBDA TEST-FUNCTION                                                          
            (FN)                                                                           
          (BLOCK TEST-FUNCTION (FUNCALL #'FN)))                                                     


test.lisp:10:3:                                                                            
  style-warning:                                                                           
    undefined function: FN                                                                 
    ==>                                                                                    
      (SB-C::%FUNCALL #'FN)

如果要调用作为参数传递的函数或分配给变量的函数,只需将变量或参数用作 funcall:

的第一个参数
(defun test-function(fn)
  (funcall fn))

(test-function #'+)
;; => 0

表示法#'X(function X)的缩写,(见manual),其中X必须是函数的名称,例如用 defunlabelsflet 或 lambda 表达式定义的。因此,#'fn 不起作用,因为 fn 不是函数的名称,而是变量(在本例中为参数)。

Common-Lisp是一个Lisp-2,就是函数的命名空间与其他变量的命名空间不同。所以函数的名字是特殊的,因为你可以直接在一个表单中调用它们,而如果一个函数被赋值给一个变量,它必须用 (funcall name-of-the-variable arguments).

来调用。

This function compiles with warnings

请注意,这些只是警告:

CL-USER> (defun test-function (fn)
           (funcall #'fn))
  1. 未使用变量FN
  2. 函数 FN 未定义。

我们来看函数:

(defun test-function (fn)   ; this introduces a variable FN
  (funcall #'fn))           ; here you use a function FN

由于范围内没有局部函数 FN,您使用的是全局函数 FN。在你的情况下,它没有定义。

以后可以定义一个全局函数FN

CL-USER> (defun fn ()
          'foobar)
FN

这已经可以工作了,因为 Common Lisp 通常还对未定义的函数使用 后期绑定,并会在运行时查找函数。

如果我们再次编译你的原始函数,那么你会看到只剩下一个警告:

CL-USER> (defun test-function (fn)     ; the variable FN is defined
           (funcall #'fn))             ; the function FN is used

;   The variable FN is defined but never used.

这是因为我们现在定义了一个全局函数FN

但是:调用全局函数可能不是您想要的,因为这样写起来更容易:

(defun test-function (fn)
  (fn))   ; calling the function `FN`.

FUNCALL 用于调用带参数的函数对象:

FUNCALL 个典型用例 是使用参数调用函数对象:

(funcall foo 1 2 3)

其中 FOO 是绑定到函数的变量。

在你的情况下,这可能是为了:

CL-USER> (defun test-function (fn)      ; a variable FN gets introduced
           (funcall fn))                ; a variable FN gets used

记住:(funcall #'foo ...)看起来不对。

如果你的代码中有类似 (funcall #'foo 1 2 3) 的东西,那么你可能做错了什么,因为它可以更容易地写成 (foo 1 2 3).

因此使用 (funcall #'foo 1 2 3) 是一种 代码味道 ,表明您可能想调用一个函数对象,但实际上您是通过它的名称调用一个函数.