Общий # lisp
В главе 3 Практически распространенной книги Lisp есть пример SQL-подобной функции select и where. Вот упрощенная версия:
(defun where (x)
#'(lambda (item)
(> item x)))
и он используется следующим образом:
(remove-if-not (where 2) (list 1 2 3 4))
Ранее в книге объясняется, что последовательность #'
используется для указания, что за ней следует имя функции, а не переменная, требующая оценки. Я не понимаю, зачем это нужно. Я попробовал реализовать функцию where
без нее, и она также работала:
(defun where (x)
(lambda (item)
(> item x)))
Я попробовал поиск по Google, и, как вы можете себе представить, с такой последовательностью символов это был не очень плодотворный поиск. И я не знаю названия этой вещи.
Есть ли какая-то конкретная причина, по которой это необходимо в приведенном выше коде?
Ответы
Ответ 1
Это точная страница в Hyperspec, которая касается стандартного макрокоманды "sharp", за которой следует "одинарная кавычка".
Чтобы сделать его простым, этот макрос читателя расширяется, чтобы заключить в форму (function <form>)
s-expression следующую форму. Это эффективно говорит парсеру, что форма является вызываемой.
lambda
- это макрос, который генерирует код, который уже содержит (function <form>)
, но исторически и для согласованности, часто используется альтернативная форма, которая получается из макроса читателя с резкой + цитатой.
Здесь Написание лямбда-выражений в общем lisp (еще один вопрос StackOverflow), в котором подробно рассматривается частный случай (lambda <form>)
Ответ 2
Примечание: *print-pretty*
- NIL
для этих примеров.
(defun where (x)
#'(lambda (item)
(> item x)))
В вышеприведенной функции where
вы создаете анонимную функцию, и вы возвращаете ее как замыкание (функция плюс привязка переменных для X
). Поскольку вы возвращаете его как значение, вам нужно написать (FUNCTION (LAMBDA ...))
. #'(lambda ...)
- это обозначение, которое короче, но приводит к тому же - используя макрос читателя #'
:
CL-USER 74 > (read-from-string "#'(lambda (foo) (1+ foo))")
(FUNCTION (LAMBDA (FOO) (1+ FOO)))
Вы также можете написать:
(defun where (x)
(lambda (item)
(> item x)))
Во время определения Common Lisp он был добавлен, чтобы писать код выше. Он также идентичен форме (FUNCTION (LAMBDA ...))
. В Common Lisp LAMBDA
находится макрос, который расширяется в нем:
CL-USER 75 > '(lambda (foo) (1+ foo))
(LAMBDA (FOO) (1+ FOO))
CL-USER 76 > (macroexpand '(lambda (foo) (1+ foo)))
(FUNCTION (LAMBDA (FOO) (1+ FOO)))
T
Итак, LAMBDA
- это макрос, и когда оценщик видит его как в (lambda ...)
, он расширяет форму до формы (FUNCTION (LAMBDA ...))
, которая затем оценивается.
FUNCTION
является специальной формой, и когда оценщик видит его, он возвращает объект функции - в случае (function (lambda (foo) (1+ foo)))
он возвращает анонимную функцию как объект:
CL-USER 77 > (function (lambda (foo) (1+ foo)))
#<anonymous interpreted function 406000761C>
Итак, вы видите, что (FUNCTION (LAMBDA ...))
- это реальная нотация s-выражения для получения объекта функции, и как #'(lambda ...)
(через макрос читателя), так и (lambda ...)
(через макрос) являются более короткими обозначениями в Lisp источнике код. Программисту необычно использовать длинную форму. Большинство (99,999%) используют одну из более коротких нот в исходном коде.
Btw: Если оценщик видит FUNCTION
, включающий имя функции, подобной этой (function sin)
, тогда она ищет привязку к функции и возвращает соответствующий объект функции:
CL-USER 78 > (function sin)
#<Function SIN 4110083C6C>