Re[13]: понимание ООП Алана Кея
От: korvin_  
Дата: 27.03.23 10:08
Оценка: 2 (1)
Здравствуйте, vdimas, Вы писали:

V>Такой дизайн. ))


Какой такой дизайн?

V>Заметь, я не говорил, что в Лиспе нельзя производить трансформацию AST явным образом, если ты напишешь свой некий такой код.


Тогда зачем ты «противопоставил» их Форту?

V>Я напоминаю, как устроены стандарные максросы Лиспа.


Тогда что значит «подстановочные»?

V>Разве?

V>

V>(defmacro foo2 (x)
V> (list 'exp x))


Разве. x — любое S-выражение, либо дерево, либо атом. Обрабатывай как хочешь.

V>В момент компиляции во внутренее представления встречающихся foo2 с аргументом x, де-факто будет происходить подстановка (list 'exp x)) с указанным x.


Потому что ты его так определил.

V>Это обычный подстановочный макрос, который может быть реализован как текстуальный/шаблонный.


Но работает он не с текстом, а с lisp-объектами.

V>На практике в Лиспе он не текстуальный по соображениям эффективности — тело макроса хранится в предкомпилённом виде, т.е. что-то вроде шаблонов С++.


Не вроде.

V>Никакого явного оперирования AST тут нет, как нет оперирования AST в шаблонах С++.


Так ты никак не оперируешь, потому что такой макрос написал. Макрос loop по-твоему тоже никак не оперирует?

(defun bindingp (expr)
  (and (= (length expr) 3)
       (destructuring-bind (var eq-sym val-expr) expr
         (eq eq-sym '=))))

(defmacro my-let (&rest body)
  (loop :while (bindingp (first body))
        :collect (first (first body)) :into variables
        :collect (third (first body)) :into expressions
        :do (setf body (rest body))
        :finally (return `((lambda ,variables ,@body) ,@expressions))))

(defun main ()
  (my-let (x = 1) (y = 2)
    (print (+ x y))))


Или что ты подразумеваешь под «оперированием AST»?

V>Эта функциональность идёт в ввиде отдельной библиотеки-интерпретатора.

V>То бишь, это независимая динамическая реализация Схемы, если ты подключаешь библиотеку-интерпретатор в программу.

V>Соответственно, у подключаемого движка-интерпретатора нет никакой связи с твоей программой.

V>В Схеме eval имеет сигнатуру (eval expression environment) где environment необходимо набить ручками перед вызовом eval.
V>Сравнить с Лиспом, в котом eval имеет сигнатуру (eval expression), а environment используется неявным образом текущий.

И что, невозможно выполнить в рантайме, в пользовательском eval Схемы define-syntax?

V>Да просто открываешь доку по макросам Лиспа и Схемы, сравниваешь.

V>Там очевидно.

Тебе сложно перечислить парочку?

V>>>Но это по-прежнему подстановочные/позиционные макросы, без явного манипулирования AST.

_>>Что мешает работать с syntax object в Схеме через syntax-case, например?

V>Это что-то вроде частичного определения шаблонов в С++ — описание неких частных случаев.

V>Механика та же, что и для общего случая.

ничего общего с шаблонами C++. И это не некие частные случаи, а возможность обрабатывать syntax-object явным образом с помощью обычных функций. Это, как раз общий случай, а syntax-rules — частный, упрощённый способ.

V>Да пофик, динамичность никуда не девается.

V>Всё-равно под капотом работает Лисп-машинка.

Как и Схем-машинка в Схеме.

_>>А eval из Схемы никуда не делся.


V>Он прямо по стандарту делся в отдельную библиотеку, которая подключается при надобности.


По которому стандарту и в какую библиотеку?

Вот смотрю, например, R5RS и не вижу упоминания библиотек.

Вот R7RS, eval наместе. Про библиотеку не сказано.

V>Идея Схемы была дать возможность исполнять конечный код без Лисп-машинки, без ссылочной семантики в >90% случаев, без динамического построения текущего контекста и поиска в нём символов (даже в компиллируемом Лиспе символы ищутся в текущем контексте динамически в процессе работы программы) и т.д.


Откуда ты взял эту идею? У cons-ячеек в Схеме ссылочная семантика и это используется в SICP.


V>>>Для целей эффективного конечного кода пришлось внести в Лисп несколько ограничений, наверно поэтому назвали другим языком и стандарты Схемы с тех пор развиваются независимо от Лиспа.

_>>Схема не так и не для этого разрабатывалась.

V>Для этого. ))

V>

V>Scheme стал первым диалектом Лиспа, применяющим исключительно статические (а не динамические) области видимости переменных


Это не говорит о цели разработки. И к компиляции/интерпретации отношения не имеет.

V>Что исключало необходимость в оперировании динамическим контекстом, позволило производить оптимизацию бинарного представления как в "обычных языках", например, оптимизацию хвостовой рекурсии. Одним словом, Схема дала ср-ва для стирания символов в конечном образе, хотя эти символы живут на этапе компиляции, скажем, в макросах.


SBCL умеет в оптимизацию хвостовой рекурсии. А в Racket есть динамический контекст в виде parameters.

V>Но при надобности не стирать символы — вот вам рядышком прежний динамический eval.



V>>>Вернее, впервые стандарты на семейство Лисп появились в Схеме — именно из-за вносимых ограничений.

_>>С чего ты взял, что из-за них?

V>Для обеспечения указанных св-в программы.

V>Там и выхода-то другого не было.
V>Поставь себя на место разработчиков такой системы, и вопросы отпадут сами собой.

Зачем мне ставить себя на их место, какое это имеет отношение к стандратизации?

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


Но при использовании CLOS этого не нужно описывать явно. Всё описано в библиотеке. И какая разница, находится это в библиотеке или зашито в рантайм языка?

V>При этом теряются гарантии целостности, в сравнении с С++, т.е. в эмуляции есть возможность описать объект, имеющий некорректный "бинарный лейаут", на котором эмуляция споткнётся в рантайм (в зависимости от реализации такой эмуляции может быть проход по памяти, либо же динамически выкинута ошибка/сигнал). В ООП-языках нет возможность описать объект некорректно, компилятор не позволяет. Даже в динамических, навроде JS или Питона, в них "объект" будет иметь корректный бинарный лейаут, "ошибки структуры объекта" будут сугубо семантические пользовательского уровня.


Какие гарантии целостности теряются в CLOS?

V>В этом абзаце имелись ввиду не встроенные объекты-символы Лиспа (числа, ф-ии и CONS), а эмулируемые "объекты" в парадигме ООП.


И что с того? Следует ли тогда стремиться вообще всё известное впихнуть в рантайм языка?

V>>>Первоклассной сущностью там являются числа/символы, функции и пара CONS(car, cdr), где каждый элемент пары может быть числом, функцией или опять парой (ссылочная семантика для всего перечисленного).

_>>И много что ещё. Перечитай определение, что такое first-class citizen.

V>Сам почитай. ))

V>

V>В C и C++ нельзя создавать функции во время выполнения программы, поэтому функции не являются объектами первого класса в этих языках. В то же время указатели на функцию можно передавать в качестве аргумента и возвращать из другой функции, поэтому иногда функции в C++ называют объектами второго класса (англ. second-class object). Тем не менее, в C++ есть понятие функционального объекта (англ. function object), который является объектом первого класса и реализует эквивалентную функциям семантику.

V>Русским по белому, что функциональный объект в С++ — это объект, эмулирующий семантику ф-ий.
V>Структура функторов в С++ известна, с т.з. компилятора — это пользовательский тип неизвестной семантики.
V>Т.е. компилятор умывает руки, просто делает то, что описано программистом.

При чём тут C и C++, когда речь шла о Лиспе? Кроме того непонятно, что автор имел в виду под «созданием функций во время выполнения программы». Что мешает подключить интерпретатор С в программу?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.