2013-11-18 4 views
2

Недавно я начал изучать Lisp. Я шел за примерами в книге Land of Lisp, и я чувствовал, что я понимала все довольно хорошо, пока я не пришел к следующему примеру вокруг главы 7:Цитата из Common Lisp

(defun quote-it (x) 
    (list 'quote x)) 

Теперь, я знаю, что list бы создать список с его аргументы, как в (list 1 2 3 4), будут оцениваться в списке (1 2 3 4).

И я также знаю, что quote позволяет мне привести аргумент, как я могу сделать с '. И так 'east - это то же самое, что и (quote east)

Теперь, интересно, функция выше не возвращает список, а просто цитирует все, что я передаю ему. нет И поэтому, если я называю это

(quote-it east) было бы просто вернуть 'east и не ('east)

Если бы я это сделал, я бы написал функцию

(defun quote-it (x) 
    (quote x)) 

И так, у меня нет подскажите, почему мы пишем команду как 'quote в (list 'quote x) в примере из книги.

Я знаю, что я могу переключаться между кодом и данными с помощью котировок, например '(+ 1 2), но в этом случае мне кажется, что я намерен фактически применить функцию котировки здесь. Итак, почему (list 'quote x)?

Итак, может ли кто-нибудь там с большим опытом прояснить это?

+1

Незначительная коррекция: '' east' - это то же самое, что '(quote east)'. –

+1

@LarsBrinkhoff Это не незначительная коррекция; вот в чем суть ответа! –

ответ

6

Исходный код Lisp представлен некоторыми из тех же структур данных, которые используются в программировании Lisp. Особое значение здесь имеют списки и символы. Когда Лисп оценивает форму, которая имеет форму

(quote something) 

, то есть, когда Лисп оценивает форму, которая представляет собой список и чей первый элемент является символом quote, то он возвращает объект somethingбез оценки его , Таким образом

(quote 2)  ;=> 2 
(quote (a b c)) ;=> (a b c) 

Теперь, это то, что оценщик (или компилятор, & с.), Когда они получают лисповским объект, чтобы оценить, что происходит, чтобы быть список, первый элемент является символом quote. Как Lisp программисты, нам все еще нужно написать код для Lisp читатель читать и передавать экзалатору.Мы можем написать длинные формы

(quote 2) 
(quote (a b c)) 

в нашем источнике, и Лиспа читатель будет читать их и передать их компилятором, но мы virtuous programmers, поэтому мы ленивы, и хотят, чтобы избежать некоторых печатать. Таким образом, мы можем ввести

'2 
'(a b c) 

вместо этого. Компилятор заканчивает получение точно такого же ввода; список, первым элементом которого является символ quote, вторым значением которого является 2 или (a b c).

Теперь мы можем поговорить о вашем коде. Форма

(list 'quote x) 

возвращает список, первый элемент которого символ quote, а второй элемент является значением переменной x. Это может быть напечатано в

(quote <value-of-x>) ; fill in x's value for <value-of-x>, of course 

Теперь Лисп принтер немного умный, и имеет возможность полиграфических вещей, как, что, используя тот же сокращенное, что мы разрешили использовать, когда мы пишем источник , Так что же можно напечатать как

'<value-of-x> 

Теперь мы получили достаточно, чтобы Ваш вопрос о коде книги:

Теперь, интересно, функция выше не возвращает список, но просто цитирует все, что я передаю. Так вот, если я называю это

(quote-it east) было бы просто вернуть 'east и не ('east)

С 'east это аббревиатура для (quote east), теперь мы видим, что (quote-it east)делает, по сути, возвращает список. И это список формы, которую вы ожидаете: список, первым элементом которого является символ quote, вторым элементом которого является символ east. Если у него было('east), он все равно вернул бы список, но он вернул бы список неправильной формы. ('east) есть, когда мы расширим аббревиатуру, список ((quote east)); то есть это список одного элемента, и этот элемент - это еще один список, первым элементом которого является символ quote, вторым элементом которого является символ east. Это, безусловно, список, но это не тот список, который вы искали.

Теперь мы можем взглянуть на ваш предлагаемый код. Ваша функция quote-it только случайно срабатывает в случае, если вы звоните (quote-it 'x). То есть, вы можете сделать

(quote-it 'x) 
;=> x 

но обратите внимание, что вы получаете символ назад, и вы получаете символ x назад. Вы являетесь не, получая список, первым элементом которого является символ quote и вторым элементом которого является <value-of-x>.При использовании quote-it с другими значениями, вы увидите проблему:

(quote-it 2) 
;=> x 

Вы еще получить символ назад, потому что

(defun quote-it (x) 
    (quote x))   ; or 'x 

принимает аргумент, связывает его с лексической переменной x , а затем возвращает значение (quote x). Какая ценность (quote x)? Как объяснялось ранее, когда оценщик (или компилятор, & c.) Получает список символов quote и something, значение представляет собой литерал something. Так как тело quote-it представляет собой список символов quote и символ x, значение тела quote-it является символом x.

+0

+1 Отличный ответ. Это именно то, что я искал. Теперь все ясно. Это часами меня било.Спасибо, Джошуа! –

+1

@EdwinDalorzo Рад быть «помощи»! –

0

Вас смущает читательский макрос. Верхний уровень
Lisp читается/Eval/печать , если вы читаете «(Foo бар) вы получите (цитата (Foo бар)) если вы Eval (цитата (Foo бар)) вы получите (Foo бар)

+0

Я не вижу, как это объясняет, что '(list 'quote x)' оценивается цитатой, а не списком. –

+0

@EdwinDalorzo '(list x y)' возвращает список, который будет напечатан как '(<значение-of-y)'. Таким образом, '(list 'quote y)' вернет список, который будет напечатан как '(quote )'. Теперь, принтер lisp может сокращать '(quote )' as '''. Форма ''' _is_ список. Это список, первым элементом которого является символ 'quote', а второй элемент -' '. –

2

Lisp имеет списки, такие как: (mary бросил мяч).

Некоторые списки описывают вычисление, как: (* PI (+ R г))

Этот первый список данных, а второе выражение подходит для оценщиком жевать.

Но нам нужен способ включения данных в выражения. Так много десятилетий назад был введен специальный оператор, который позволил бы это сделать, например: (count-существительные (цитата (mary бросила мяч))

Прошло время, и разработчикам надоело вводить (цитировать ...), поэтому они придумали короткую нотную запись: (count-существительные (мари бросил мяч)).

В эти дни сокращенная версия реализована во время чтения, так как символы считываются из файла или с терминала. Это делается с помощью средства, известного как «считывающие макросы». Это имя сбивает с толку большинство новичков, поскольку на языке, называемом «макросы», есть еще одно средство, которое действительно имеет мало общего с чтением файлов. Они обычно используются для добавления небольшого синтаксического сахара. Как в этом примере цитаты. После того, как поток файлов (или терминалов) был прочитан, все это всего лишь список.

Вы заметите, что если вы введете: (quote bob) в свой запрос lisp, вы вернетесь: 'bob. Принтер хорошо осведомлен о соглашении, которое (quote bob) имеет сокращенную форму. Если вы когда-нибудь решите написать свои собственные макросы для чтения, вы можете научить принтера, как играть.

Макросы, как v.s. читайте макросы, позвольте вам представить свои собственные специальные операторы. И это позволяет вам встраивать пользовательские языки, специфичные для домена, в ваш код. Итак - вид макроса позволяет расширять семантику и макросы чтения, чтобы вы могли расширить синтаксис. Макросы влияют на поведение компилятора и оценщика.

4

Пример: Если вы хотите создать список с символом foo и переменным числом:

  • мы имеем ряд
  • мы хотим, чтобы сделать список (foo <some-number>)

Теперь мы напишите надписью для нее:

(defun foo-it (n) 
    (list 'foo n)) 

Очевидно,

(defun foo-it-1 (n) 
    (foo n)) 

Не сработает. Он будет вызывать функцию FOO на n вместо создания списка.

(defun foo-it-2 (n) 
    '(foo n)) 

Выше также не работает, так как список (foo n) не вычисляется и возвращается как есть.

Теперь Лисп имеет кавычка синтаксис:

(defun foo-it-3 (n) 
    `(foo ,n)) 

Выше будет работать. Запятая отмечает, что будет оценен символ n.

Для вашей проблемы. Заменить foo с quote:

(list 'foo n) -> (list 'quote n) 

или

`(foo ,n) ->  `(quote ,n) 

Основное отличие состоит в том, что Лисп принтер всегда будет печатать (foo 3) в (foo 3). FOO не имеет специального назначения. Но QUOTE имеет (потому что он определен на языке), и принтер Lisp может печатать (quote 3) как '3.

Пример:

CL-USER 14 > (progn 
       (write (list 'foo 3) :pretty nil) 
       (terpri) 
       (write (list 'foo 3) :pretty t) 
       (values)) 
(FOO 3) 
(FOO 3) 

CL-USER 15 > (progn 
       (write (list 'quote 3) :pretty nil) 
       (terpri) 
       (write (list 'quote 3) :pretty t) 
       (values)) 
(QUOTE 3) 
'3 

Это только потому, что в Лиспе, то quote характер определяется встроенным в синтаксисе и принтер знает об этом.

Также обратите внимание, что печать также модифицируется набором специальных символов, таких как *print-pretty*, *print-readably*, .... Так что разные настройки Lisp могут печатать разные, в зависимости от настроек этих переменных.

+0

Еще одно замечательное объяснение. Вот, мой голос +1 –