Подтвердить что ты не робот

Общий # 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, и, как вы можете себе представить, с такой последовательностью символов это был не очень плодотворный поиск. И я не знаю названия этой вещи. Есть ли какая-то конкретная причина, по которой это необходимо в приведенном выше коде?

4b9b3361

Ответ 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>