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

Сам себе Гринспун

Вощем, читать исходный текст и строить дерево кода по нему проще, если каждый новый токен добавляется в начало текущей ветки, а потом, когда уже весь файл прочитан, дерево всё чохом переворачивается.

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

Пока до меня это дошло, выпил литра три кофе. Да, я до сих пор сижу за компом - не могу заснуть, чортовы CAR и CDR крутятся перед глазами.

Надо ещё подсократить количество копирований списков, а то есть лишние туда-сюда перемещения данных. Не то шоб оно сильно мешало, но
1) неаккуратно
2) неоптимально
3) медленно
4) не имеет реального смысла, т.е. "неразрушающее присваивание" это идеологически рядом, но всё же из другой оперы.


Какой же Джон Маккарти умище был, я охреневаю.

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


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

Program code tree:
(

( DEFSYM Z "Zet" ) ; создаём символ, присваиваем ему значение

( DEFUN FOO ( X Y ) ; описываем функцию двух переменных
( PROGN
( DEFSYM Z 10 ) ; здесь переопределим символ.
; Если строку закомментировать, то следующая должна вывести значение из "верхнего" контекста
( FORMAT "FOO: X: ~a; Y: ~a; Z: ~a~%" X Y Z )
)
)

( DEFUN BAR ( X Y Z )
( PROGN
( FOO 1 2 ) ; тут мы вызываем фуцнкцию, имена которой совпадают с нашими. Засрёт контекст или нет? Вот в чём вопрос!
( FORMAT "BAR: X: ~a; Y: ~a; Z: ~a~%" X Y Z )
)
)

( BAR 4 5 6 )
( FORMAT "Z: ~a~%" Z )
)
================================================================= Main evaluation cycle: START
FOO: X: 1; Y: 2; Z: 10
BAR: X: 4; Y: 5; Z: 6
Z: "Zet"
================================================================= Main evaluation cycle: END

Как видим, немнотря на явную попытку внутри функции FOO создать символ Z и присвоить ему значение 10, контекст верхнего уровня об этом ничего не знает. Так же как значения X,Y,Z в контексте BAR понятия не имеют, что внутри вызова FOO они были иными. Круть!




Одно из возможных практических применений моего конструкции - пересылка сообщений между объектами. Вместо того, чтобы из одного объекта дёргать функции другого объекта, мы можем в буквальном смысле присылать кусочки кода, данных или всё вместе. Насколько я понимаю, парсер получается потокобезопасный - никаких глобальных и/или статических переменных, от которых было бы сложно отказаться, у меня нет. Дерево кода хранится в списке, который (разумеется) создаётся динамически. Функция eval(), в которой вся мощь, получает тэгированный указатель, анализирует его и либо вызывает процедуру (если она есть), создав локальный контекст, либо сразу вычисляет "самоочевидное" значение. Какой указатель скормим, такой результат и получим, какого-то внутреннего состояния, приколоченного гвоздями, нет.
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 

  • 0 comments