Common Lisp,"已定义但从未使用"

时间:2016-09-25 20:33:49

标签: lisp common-lisp lisp-2 funcall

此函数编译警告, fn 已定义且从未在第一行使用, fn 是第二行中未定义的函数:

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

为什么呢?一般性解释或其链接将很棒。

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)

2 个答案:

答案 0 :(得分:7)

如果要调用作为参数传递的函数或分配给变量,只需使用变量或参数作为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)调用。

答案 1 :(得分:4)

  

此功能编译警告

请注意,这些只是警告:

CL-USER> (defun test-function (fn)
           (funcall #'fn))
  1. 未使用变量FN
  2. 函数FN未定义。
  3. 让我们看一下这个函数:

    (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)是一个代码气味,表明你可能想调用一个函数对象,但实际上是通过它的名字调用一个函数。