‮Сдвиг по фазе (kincajou) wrote,
‮Сдвиг по фазе
kincajou

<a>Ленин</a>

(В заголовке - старинный каламбур про Ленина в ссылке.)

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

Вот, например, как мы делаем в Си, если хотим присвоить какой-то переменной какое-то значение:
int a = 2;
Как это делается в Лиспе (один из способов):
(setf a 2)
Внешняя схожесть заканчивается, если начать разбираться в деталях реализации. В Си имя переменной - это имя, присвоенное адресу в памяти на этапе компиляции. Один раз объявив переменную, мы её "прибиваем гвоздями" к определённому месту в памяти, читать-писать которое можно будет только одним определённым способом. Каким именно, подсказывает нам прописанный "тип переменной" (в примере выше это "int"): компилятор запоминает это указание и в дальнейшем использует специальные последовательности команд, которые "знают" про то, как значение определённого типа размещается в памяти.

В Лиспе имя переменной это.. ээ.. ну, в общем, просто имя. Оно является чем-то вроде ключа для поиска по пространству имён - когда мы хотим получить значение переменной A, лисп-машина запускает процедуру поиска ассоциированного с этим именем значения. Когда оно найдено, оно же и возвращается - с т.з. прикладного программиста ничего особо сложного. На деле же, внутри этого "значения" содержится вся информация, требуемая для работы с ним - указание, какой конкретно тип это значение имеет, где физически оно находится в памяти машины и т.п.

На этом этапе всё довольно просто. Сложности начинаются чуть позже...

В Лиспе есть красивый механизм ссылок, позволяющий делать такие вещи (ниже приведён гипотетический сеанс работы с гипотетической лисп-машиной, где пользователь вводит свои команды в ответ на приглашение в консоли CL:, а машина потом печатает ответ):
CL: (setf f (list 1 2 3))
( 1 2 3 )
CL: (car f)
1
CL: (cdr f)
( 2 3 )
CL: (setf (car f) "Horray!")
"Horray!"
CL: f
( "Horray!" 2 3 )


В этом (повторю: сугубо гипотетическом!) примере пользователь создаёт список f, потом смотрит на его "голову" (и видит "1"), на "хвост" (и видит "( 2 3 )"), а потом присваивает "голове" списка новое значение. И что самое поразительное, значение в самом деле изменяется - список теперь содержит строку "Horray!" в качестве первого элемента.

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

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

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

Но идея с тэгированным указателями, сработавшая для различения "списков" от "не-списков", должна помочь и тут - при помощи тэга можно будет различать "указатель на значение" от "указателя на указатель на значение" - а весь код, который будет распутывать эти хитросплетения, спрятать где-то глубоко внутри.
Tags: uncommon lisp
Subscribe
  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 15 comments