Сценарий цитирования странного Lisp — книга Грэма On Lisp, стр. 37

StackOverflow https://stackoverflow.com/questions/4003115

Вопрос

Я просматриваю книгу Грэма «О Лиспе» и не могу понять следующий пример на странице 37:

If we define exclaim so that its return value
incorporates a quoted list,

(defun exclaim (expression)
  (append expression ’(oh my)))

>  (exclaim ’(lions and tigers and bears))
(LIONS AND TIGERS AND BEARS OH MY)
> (nconc * ’(goodness))
(LIONS AND TIGERS AND BEARS OH MY GOODNESS)

could alter the list within the function:

> (exclaim ’(fixnums and bignums and floats))
(FIXNUMS AND BIGNUMS AND FLOATS OH MY GOODNESS)

To make exclaim proof against such problems, it should be written:
(defun exclaim (expression)
  (append expression (list ’oh ’my)))

Кто-нибудь понимает, что здесь происходит?Это серьезно противоречит моей мысленной модели того, что делает цитирование.

Это было полезно?

Решение

nconc — это деструктивная операция, которая изменяет свой первый аргумент, изменяя его хвост.В данном случае это означает, что постоянный список '(oh my) получит новый хвост.

Надеюсь, чтобы сделать это яснее.Это примерно так:

; Hidden variable inside exclaim
oh_my = oh → my → nil

(exclaim '(lions and tigers and bears)) =
    lions → and → tigers → and → bears → oh_my

(nconc * '(goodness)) destructively appends goodness to the last result:
    lions → and → tigers → and → bears → oh → my → goodness → nil
so now, oh_my = oh → my → goodness → nil

Замена '(oh my) с (list 'oh 'my) исправляет это, потому что больше нет константы, разделяемой всеми и каждым.Каждый звонок в exclaim генерирует новый список ( list жизненная цель функции — создание совершенно новых списков).

Другие советы

Наблюдение в том, что ваша ментальная модель цитаты может быть ошибочной, является отличным - хотя она может или не может применяться в зависимости от того, что такое умственная модель.

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

Давайте поставим вопрос о компиляции в сторону в сторону и сосредоточиться на этапах чтения и оценки, предполагая (для простоты), что вход оценщика является список структур данных, прочитанных читателем.

Рассмотреть форму (QUOTE x) куда Икс это некоторое текстовое представление объекта. Это может быть символ литерала, как в (QUOTE ABC), список литерала как в (QUOTE (A B C)), строковая буквальная как в (QUOTE "abc"), или любой другой вид литерала. На этапе чтения читатель будет прочитать форму в виде списка (вызовите его Форма1.) Чей первый элемент является символом QUOTE и чей второй элемент является объектом Икс' Чье текстовое представление Икс. Отказ Обратите внимание, что я специально говоря, что объект Икс' хранится в списке, который представляет выражение, т.е. в некотором смысле, он хранится как часть самого кода.

Теперь это поворот оценщика. Ввод оценщика Форма1., который является списком. Так что он смотрит на первый элемент Форма1., и, установив, что это символ QUOTE, Он возвращается в результате оценки второго элемента списка. Отказ Это решающая точка. Оценщик возвращает второй элемент списка, который будет оцениваться, что является тем, что читатель читает на первом этапе выполнения (до компиляции!). Это все, что это делает. На нем нет магии, это очень просто, и значительно, новые объекты не создаются, и никакие существующие не копируются.

Поэтому всякий раз, когда вы изменяете «цитируемый список», вы модифицируете сам код. Отказ Самомодифицирующий код - это очень запутанная вещь, и в этом случае поведение на самом деле неопределено (поскольку ANSI Common Lisp позволяет реализациям поставить код в памяти только для чтения).

Конечно, вышеизложенное - просто умственная модель. Реализации могут свободно реализовать модель различными способами, и на самом деле я не знаю не реализацию общих веществ, которые, как и мое объяснение, вообще не компиляции. Тем не менее, это основная идея.

В общем лиспе.

Запомнить:

'(1 2 3 4)

Выше это А. буквальный список. Постоянные данные.

(list 1 2 3 4)

Список - это функция, что при возврате вызова Свежий новый список С его аргументами как элементы списка.

Избегайте модификации литеральных списков. Эффекты не стандартизированы. Представьте себе Lisp, который компилирует все постоянные данные в область памяти только на запись только. Представьте себе Lisp, который принимает постоянные списки и разделяет их по функциям.

(defun a () '(1 2 3)

(defun b () '(1 2 3))

Компилятор Lisp может создать один список, который передается обеими функциями.

Если вы измените список, возвращаемый функцией A

  • Это может не быть изменено
  • Это может быть изменено
  • Это может быть ошибка
  • Это может также изменить список, возвращаемый функцией B

Реализации имеют свободу делать то, что им нравится. Это листья комнаты для оптимизаций.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top