Ответ 1
Прежде чем переходить к некоторым вещам, я хотел бы добавить еще один ответ, вот еще одна ссылка - часть, связанная с гомоконичностью, довольно короткая, но Rich Hickey делает объяснение! Канал 9 имеет это приятное видео с Ричем Хики и Брайаном Бекманом, говорящим о Clojure. Concurrency, по понятным причинам, основной фокус, но гомоконичность действительно дает свой (короткий) момент времени экрана, в течение которого Rich прекрасно объясняет взаимодействие между read
(функция, которая преобразует конкретный синтаксис, записанный программистом на внутреннее представление, построенное из списков и т.д.) и eval
. У него есть эта хорошая диаграмма, показывающая, как eval
никогда даже не знает, что код, который он оценивает, исходит из read
, работающего в текстовом файле... Артур уже объяснил суть этого, но эй, посмотри это в любом случае, это очень приятное видео!
Отказ от ответственности: я буду упоминать Java и Python в качестве примеров ниже следующей горизонтальной полосы. Я хочу пояснить, что следующее - это всего лишь примерный пример того, почему я думаю, что может быть сложно сделать homoiconic, Lisp -строчную макроуровню Java или Python; это просто академическое упражнение, и я не хочу рассматривать вопрос о том, есть ли какая-то причина, чтобы попытаться в первую очередь. Кроме того, я не хочу подразумевать, что синтаксис языка с макросами стиля Lisp должен содержать явные разделители для древовидных структур; Дилан (безразмерный Lisp?), По-видимому, обеспечивает контрпример. Наконец, я использую макросы стиля Lisp, потому что я рассматриваю только макросы стиля Lisp. Например, у языка Forth есть другое средство макросов, которое я действительно не понимаю, за исключением того, что я знаю его, чтобы включить злой классный код. По-видимому, расширения синтаксиса могут быть реализованы несколькими способами. С этим в сторону...
Я хотел бы затронуть вторую часть вашего вопроса - как многие языки программирования считаются не гомохимическими? Я должен затронуть семантику Lisp в процессе, но так как Нильс уже предоставил ссылки на хорошие источники информации о термине "homoiconic", и Артур описал цикл чтения → macro expand → compile как показано в Clojure, я буду строить это в дальнейшем. Чтобы начать все, позвольте мне процитировать отрывок из Алана Кей (извлеченный из статьи Википедии, которая также ссылается на исходный источник):
[...] Интерактивный Lisp [...] и TRAC [...] оба являются "homoiconic" тем, что их внутренние и внешние представления по существу одинаковы.
(Эти [...] биты спрятали много текста, но суть не изменилась.)
Теперь задайте себе вопрос: что такое внутреннее представление Java Java?... Ну, это даже не имеет смысла. Компилятор Java имеет определенное внутреннее представление Java, а именно абстрактное синтаксическое дерево; для построения "гомозвуковой Java" мы должны были бы сделать это представление АСТ первоклассным объектом в Java и разработать синтаксис, который позволит нам напрямую писать АСТ. Это может оказаться довольно сложным.
Python представляет собой пример негомиконического языка, который интересен тем, что в настоящее время он поставляется с набором инструментов для управления АСТ в форме модуля ast
. Документы для этого модуля явно указывают, что АСТ Python могут меняться между релизами, что может или не может обескураживать; Тем не менее, я полагаю, что трудолюбивый программист может взять модуль ast
, разработать синтаксис (возможно, основан на S-выражении, возможно, на основе XML) для непосредственного описания АСТ Python и построить парсер для этого синтаксиса в обычном Python с использованием ast
, тем самым сделав твердый первый шаг на пути к созданию гомоязычного языка с семантикой Python. (По-моему, я натолкнулся на диалект Lisp, компилирующий байт-код Python некоторое время назад... Интересно, может ли это делать что-то подобное на каком-то уровне?)
Даже тогда проблема остается в извлечении конкретных выгод от такого рода гомоконичности. Он рассматривается как выгодное свойство членов семейства языков Lisp, потому что он позволяет нам писать программы, которые пишут дальнейшие программы, среди которых наиболее важные макросы. Теперь , в то время как макросы включены одним способом из-за того, что так легко манипулировать внутренним представлением кода Lisp в Lisp, они также включены не менее важным способом при выполнении Lisp модель: a Lisp - это просто набор форм Lisp; они обрабатываются функцией Lisp eval
, которая отвечает за определение значений выражений и вызывает соответствующие побочные эффекты в правильное время; семантика Lisp является в точности семантикой eval
. Вопрос о том, как все работает внутренне, чтобы сохранить эту смысловую иллюзию, будучи достаточно быстрым, представляет собой деталь реализации; a Lisp система обязана выставить функции eval
программисту и действовать так, как если бы Lisp программы обрабатывались этой функцией.
В современных системах Lisp входит в контракт eval
, что он выполняет дополнительную фазу предварительной обработки, в ходе которой макросы расширяются до оценки кода (или компиляции и работы, в зависимости от ситуации). Это конкретное средство не является необходимой частью системы Lisp, но ее легко подключить к этой модели исполнения! Кроме того, я задаюсь вопросом, не является ли это не единственной моделью выполнения, которая делает типы макроформаций Lisp управляемыми, что означало бы, что любой язык, требующий включения макросов Lisp -style, должен был бы использовать аналогичную модель исполнения. Моя интуиция подсказывает мне, что это действительно так.
Конечно, как только язык записывается в нотации, непосредственно параллельной его АСТ, и использует Lisp -подобную модель исполнения с функцией/объектом оценщика, нужно задаться вопросом, не случайно ли это другой диалект Lisp... даже если его синтаксис AST-параллелизма основан на XML. Дрожь