Почему я должен вызывать функцию, возвращенную из другой?
Почему это не работает?
( ((lambda () (lambda (x) (funcall #'1+ x)))) 2)
; yields Compile-time error: illegal function call
Я столкнулся с такой ситуацией, и позже оказалось, что funcall
исправляет это, т.е.
(funcall ((lambda () (lambda (x) (funcall #'1+ x)))) 2) ; => 3
Я сбит с толку, потому что кажется, что первый должен работать, потому что у меня есть функция, которую я вызываю, а не просто символ, который может принадлежать какому-либо пространству имен (т.е. (type-of ((lambda () #'1+))) ; => FUNCTION
). Я думал, это будет похоже на то, что тебе не нужно funcall
лямбда, например, например((lambda (x) x) :HI) ; => :HI
, Что мне не хватает?
4 ответа
Синтаксис Common Lisp требует, чтобы каждый раз, когда вы хотите вызвать функцию через форму compund типа:
(f a1 a2 ... an)
первый элемент списка, f
, должен быть символом, обозначающим имя функции, или списком, обозначающим лямбда-выражение, т.е. (см. руководство):
лямбда-выражение n. список, который может использоваться вместо имени функции в определенных контекстах для обозначения функции путем непосредственного описания ее поведения, а не косвенно путем ссылки на имя установленной функции; его название происходит от того факта, что его первым элементом является символ лямбда.
Таким образом, это в основном означает, что вы не можете иметь в качестве первого элемента любое выражение, которое возвращает функцию в качестве значения. В этих случаях вы должны использовать funcall
,
Итак, во втором примере первый аргумент funcall
является ((lambda () (lambda (x) (funcall #'1+ x))))
, которая является правильной формой, в которой первым элементом списка является лямбда-выражение (lambda () (lambda (x) (funcall #'1+ x)))
(применяется к пустому списку аргументов).
В первом примере вместо этого у вас в качестве первого элемента списка есть выражение, возвращающее функцию, так что вы должны использовать funcall
,
Common Lisp использует словоформу для всего, что может быть оценено. Форма это либо
- символ как
foo
- составная форма, список, см. ниже
- или самооценочный объект (например, числа, символы, массивы, строки,...).
Составная форма является либо
- особая форма
(<special-operator> ...)
- лямбда-форма как
(lambda (...) ...)
- форма макроса
(<macroname> ...)
- или форма функции
(<functionname> ...)
,
Выше множество сложных форм. Спецификация ANSI Common Lisp не позволяет добавлять новый тип форм или другой синтаксис. Интерфейс того, что формирует функции как EVAL
или же COMPILE
принять не расширяемый.
Так что-то вроде
(((lambda (foo)
(lambda (bar)
(list foo bar)))
1)
2)
не действителен Common Lisp. Это не имеет смысла в Common Lisp:
( <not a lambda form,
not a special operator,
not a macro name
and not a function name>
2)
Обратите внимание, что Common Lisp допускает лямбда-формы, специальные операторы, имена макросов и имена функций в качестве первого элемента в составной форме. Но он не допускает переменных и не допускает других составных форм в качестве первого элемента в составной форме.
Означает, что это не имеет смысла в Common Lisp:
( <a function form> 2)
таким образом ((foo 1) 2)
или же (((foo 1) 2) 3)
или же ((((foo 1) 2) 3) 4)
или же (((((foo 1) 2) 3) 4) 5)
не является законным в Common Lisp. Вы поняли идею. Для вызова объектов функций, возвращаемых из вызовов функций, мы должны использовать (funcall (foo ...) ...)
, Это делает вызов возвращаемых объектов-функций более очевидным, чем просто ((foo ...) ...)
,
Давайте похвалим разработчиков Common Lisp за эту функцию. В противном случае мне, возможно, придется взглянуть на возможно значимый код, начинающийся с
(((((((((((( .....
и было бы очень трудно понять, что он делает. В основном это будет код только для записи.
Ваш вопрос:
Почему я должен вызывать функцию, возвращенную из другой?
Краткий ответ: потому что синтаксис не позволяет другие пути, в Common Lisp.
Это работает: сначала ваши идентичные определения:
(defparameter *my-fun* 1)
(defun my-func (v0)
(setf (symbol-function '*my-fun*)
(lambda (v1)
(+ v0 v1)))
'*my-fun*)
Тем не менее, вызовите используя funcall:
(funcall (my-func 2) 3)
Я прочитал эту статью, а затем изменил свой код ниже:
(defparameter *my-fun* 1)
(defun my-func (v0)
(setf (symbol-function '*my-fun*)
(lambda (v1)
(+ v0 v1)))
'*my-fun*)
И назови это так ((my-func 2) 3)
, но он также сообщает о "незаконном вызове функции". Я думаю, что мой код соответствует лямбда-исчислению, но где это не так.
По моему мнению, (my-func 2) возвращает символ * my_fun *, а ячейка функции * my-fun * указывает на функциональный объект, поэтому ((my-func 2) 3) => (*my-fun* 3) => ((лямбда (v1) (+ 2 v1)) 3) => (+ 2 3) => 5