Common Lisp, "определенный, но никогда не используемый"
Эта функция компилируется с предупреждениями, 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 ответа
Если вы хотите вызвать функцию, переданную в качестве параметра или присвоенную переменной, просто используйте переменную или параметр в качестве первого аргумента для funcall
:
(defun test-function(fn)
(funcall fn))
(test-function #'+)
;; => 0
Запись #'X
это сокращение от (function X)
, (см. руководство), где X
должно быть именем функции, например, определенной с помощью defun
или же labels
или же flet
или лямбда-выражение. Так, #'fn
не работает с fn
это не имя функции, а переменная (в данном случае параметр).
Common-Lisp - это Lisp-2, то есть пространство имен функций отличается от пространства имен других переменных. Таким образом, имена функций являются особыми в том смысле, что вы можете вызывать их непосредственно в форме, в то время как, если функция назначена переменной, она должна вызываться с помощью (funcall name-of-the-variable arguments)
,
Эта функция компилируется с предупреждениями
Обратите внимание, что это только предупреждения:
CL-USER> (defun test-function (fn)
(funcall #'fn))
- переменная
FN
не используется - функция
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)
указывает на то, что вы, вероятно, хотели вызвать объект функции, но на самом деле вы вызываете функцию через ее имя.