Разница между (список 1 2 3 4) и '(1 2 3 4)? - PullRequest
0 голосов
/ 21 мая 2018

Вот мой код:

(format t "~a~%" (list 1 2 3 4))
(format t "~a~%" '(1 2 3 4))
(format t "~a~%" (remove-if-not #'evenp (list 1 2 3 4)))
(format t "~a~%" (remove-if-not #'evenp '(1 2 3 4)))

Вот вывод:

$ clisp bar.lisp 
(1 2 3 4)
(1 2 3 4)
(2 4)
(2 4)

Мои вопросы:

  1. В чем разница между двумяСинтаксис: (list 1 2 3 4) и '(1 2 3 4)?
  2. Есть ли преимущество использования одного синтаксиса перед другим?

Ответы [ 2 ]

0 голосов
/ 21 мая 2018

Разница в том, когда список создается.Один создается reader , другой в runtime .

Читатель отвечает за преобразование вашего текстового файла в структуру данных, представляющую код.Эта структура данных в основном состоит из списков;это идея Lisp (LISt Processing).

Когда читатель читает текст (foo bar), он создает список из двух элементов, а именно символов foo и bar.Затем он компилируется, то есть переводится, в вызов функции (или другой вызов, но не будем здесь останавливаться), где функция с именем foo вызывается со значением переменной с именем bar.

Существует специальный оператор, который сообщает компилятору , а не , чтобы сделать этот перевод: quote.Когда компилятор встречает список (созданный читателем) (quote (foo bar)), он использует вещь, «защищенную» quote буквально , то есть именно этот список (foo bar), созданныйчитатель.

Апостроф ' является сокращением для quote, поэтому '(foo bar) читается как (quote (foo bar)).

Форма '(1 2 3), таким образом, является именно тем списком, которыйВы написали в свой текстовый файл, как прочитано читателем.Это называется литеральным списком .

С другой стороны, (list 1 2 3) является обычным вызовом функции list с тремя аргументами.Он создает новый список этих аргументов каждый раз, когда этот код выполняется во время выполнения.

Вы должны использовать список литералов, только если он постоянен.Например, при создании многомерного массива вы можете знать, что его размер всегда одинаков (возможно, это свойственно проблеме), поэтому вы пишете (make-array '(3 5)).Если вы хотите сделать его настраиваемым, вы должны его параметризовать: (make-array (list width height)).

Единственное, чего вам абсолютно необходимо избегать, это модифицировать литеральные данные.

0 голосов
/ 21 мая 2018

Разница между '(1 2 3 4) и (list 1 2 3 4), которые, похоже, возвращают абсолютно одинаковый результат (1 2 3 4), не видна, потому что числа в Лиспе оценивают сами себя.

Вместо чисел берут символы или выражения:

(list (+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5))
;; returns/evaluates to:
(3 5 7 9) ;; each of the arguments in a list gets evaluated.


;; while:
'((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)) ;; equals to: (quote ((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)))
;; returns/evaluates to:
((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)) ;; arguments of list not evaluated
;; since `quote` means: take the argument as data - unevaluated.

Теперь вы ясно видите разницу: '(1 2 3 4) расширяется до (и, следовательно, является синтаксическим сахаром до) (quote (1 2 3 4)) - это специальная форма , тогда как (list 1 2 3 4) - это функция . Функции в Лиспе оценивают каждый из своих аргументов . Но специальные формы не оценивают каждый из своих аргументов. В случае quote аргумент quote не оценивается.

И теперь вы видите, с a, b, c, d, не определенными ранее, это

'(a b c d) 
;; returns: (A B C D)

работает, так как abcd не оценивается!

Но это:

(list a b c d)

вызывает ошибку:

*** - SYSTEM::READ-EVAL-PRINT: variable A has no value
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of A.
STORE-VALUE    :R2      Input a new value for A.
ABORT          :R3      Abort main loop

, поскольку ни a, ни b, ни c, ни d еще не определеныно интерпретатор Lisp пытается их оценить, так как они являются аргументами функции.

Но вы все равно можете получить (A B C D), используя функцию list, заключив в кавычки каждый из аргументов - таким образом, заставив их вычислить их имена символоввместо интерпретатора Lisp для поиска их неопределенных значений:

(list 'a 'b 'c 'd)
;; now it works - though a b c d are not defined yet:
(A B C D)

Примечание: Интересно, что не во всех языках аргументы функции оцениваются только потому, что они являются аргументами функции.В то время как Python оценивает все аргументы своей функции, аналогичные Lisp до ввода и вычисления тела функции, R не делает этого.

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

Это также одна из причин, по которой вам также нужно изучать макросы (которые задают специальные формы) в Lisp.quote вместе с list фактически является матерью всех макросов.Любые операции backquote и unquote могут быть выражены через quote и list (хотя для человеческого читателя это выглядит неприятнее).Можно долго размышлять на эту тему, как вы можете себе представить.И ваш вопрос касается непосредственно сути и сути того, что делает Лисп таким восхитительным.

...