Видимый eval символа кавычки в CLISP

Некоторые выходные данные CLISP REPL:

[1]> (list 'list 1 2 3)
(LIST 1 2 3)

[2]> (list 'list '(1 2 3))
(LIST (1 2 3))

[3]> (list 'quote 1 2 3)
(QUOTE 1 2 3)

[4]> (list 'quote '(1 2 3))
'(1 2 3)

Первые три, я точно понимаю, что происходит: функции list передается символ ('list или 'quote), поэтому в результате получается список, который начинается с символа list или quote. Меня смущает четвертый. Почему не возвращается (QUOTE (1 2 3))?

Я понимаю, что если вы введете (QUOTE '(1 2 3)) в REPL, вы получите '(1 2 3) обратно, так что выражения эквивалентны в этом смысле. Но (LIST 1 2 3) эквивалентно (1 2 3), и все же первое выражение этого не возвращает.

Кажется несостоятельным, что (list 'quote 1 2 3) возвращает список с первым элементом, являющимся символом quote, а (list 'quote (1 2 3)) возвращает список в кавычках. Тем более, что такие выражения, как (list 'list ...), похоже, всегда возвращают список, начинающийся с символа - пока, по крайней мере, quote является единственным подобным «особым случаем».

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


person djh    schedule 13.08.2015    source источник
comment
Scheme и Common Lisp - это разные языки, но вы можете найти '(цитата) в схеме полезным, поскольку проблема заключается в тем же. Еще несколько релевантных ссылок (и возможных дубликатов) можно найти в этом комментарии .   -  person Joshua Taylor    schedule 13.08.2015


Ответы (2)


'something то же самое, что (quote something) для читателя lisp. Даже когда они вложены друг в друга, это будет так. Следующие выражения я заключу в двойные кавычки, чтобы после вычисления одна из кавычек все еще оставалась там.

При печати реализации могут выбирать, что выводить, где есть несколько возможных представлений, поэтому некоторые реализации будут печатать оценку ''something как (quote something), в то время как другие могут использовать сокращение 'something.

'(quote 1 2 3) не может быть сокращен, поскольку цитируемая форма имеет только один аргумент. Таким образом, здесь обе системы lisp будут печатать (quote 1 2 3).

Вот способ взглянуть на ваше последнее выражение:

(let ((data (list 'quote '(1 2 3))))
  (format nil 
          "whole thing: ~a first element: ~a second-element: ~a" 
          data 
          (car data) 
          (cadr data)))

Это будет либо "whole thing: '(1 2 3) first element: QUOTE second-element: (1 2 3)", либо "whole thing: (QUOTE (1 2 3)) first element: QUOTE second-element: (1 2 3)".

Поскольку принтер никогда не видит, сокращен ли ввод и данные имеют ту же структуру в памяти, то на вывод не влияет то, как вы вводите данные. Таким образом, (quote (quote (1 2 3))) будет печатать то же, что и ''(1 2 3).

У вас такое же поведение с cons ячейками, но стандарт диктует правила. (cons 1 (cons 2 (cons 3 '()))) будет (1 . (2 . (3 . ()))), но на самом деле он просто напечатан (1 2 3) Однако, если вы (cons 1 2), вы получите (1 . 2), показывающий, что print обрабатывает вывод по-разному в зависимости от cdr. Однако читатель может прочитать любой из них, и все они напечатают одно и то же, например. '(1 . (2 . (3 . ()))) ==> (1 2 3) и (+ . (2 . ( 3 . ()))) ; ==> 5

Числа могут иметь столько визуальных форм, сколько оснований под рассматриваемым числом.

(let ((*print-base* 16))
  (print 255)) ; prints FF (255 in hexadecimal)

list не имеет аббревиатуры или специального назначения в Лиспе. Это даже не примитивная функция, но она очень полезна, поскольку устраняет неудобство, связанное с необходимостью постоянно проверять недостатки вручную. Это можно определить так:

(defun my-list (&rest lst)
  lst)

(my-list 1 2 3 4) ; ==> (1 2 3 4)
person Sylwester    schedule 13.08.2015
comment
Спасибо! Думаю, я понял это сейчас - person djh; 13.08.2015

Обратите внимание, что REPL (READ-EVAL-PRINT-LOOP) выполняет три функции:

  • чтение с использованием функции READ
  • оценка с использованием функции EVAL
  • и распечатать результат, используя что-то вроде функции PRINT

Чтобы понять, что происходит, вы должны посмотреть на все три функции.

Давайте посмотрим на третью форму:

(list 'quote 1 2 3)

Это читается как список из пяти элементов:

  1. LIST
  2. (QUOTE QUOTE)
  3. 1
  4. 2
  5. 3

EVAL затем оценивает аргументы, вызывает функцию list с четырьмя результатами и возвращает новый результат, список из четырех элементов:

  1. QUOTE
  2. 1
  3. 2
  4. 3

PRINT затем берет этот список и записывает его как: (QUOTE 1 2 3). Сокращенного способа распечатать его не существует.

Давайте посмотрим на четвертую форму:

(list 'quote '(1 2 3))

Это читается как список из трех элементов:

  1. LIST
  2. (QUOTE QUOTE)
  3. (QUOTE (1 2 3))

eval вызывает list с двумя аргументами:

  1. QUOTE
  2. (1 2 3)

eval затем возвращает список длиной два:

  1. QUOTE
  2. (1 2 3)

print теперь можно распечатать этот список двумя разными способами:

(QUOTE (1 2 3)) или сокращенная форма '(1 2 3). Здесь кавычка стоит перед одним выражением.

Ваша реализация использовала первую версию.

person Rainer Joswig    schedule 14.08.2015