«Homoiconic» - своего рода нечеткая конструкция. «Код - это данные» немного понятнее.
В любом случае, первое предложение в Википедии для Homoiconic не так уж и плохо. В нем говорится, что язык должен иметь исходное представление, используя его структуры данных . Если мы забываем «строки» в качестве исходного представления (это тривиально и не очень полезно иметь полезную концепцию «гомо-звонное»), тогда в Лиспе есть списки, символы, числа, строки и т. Д., Которые используются для представления исходного кода. Интерфейс функции EVAL определяет тип представления источника, на котором работает язык. В этом случае, Лисп, это не строки. EVAL ожидает, что обычное разнообразие структур данных и правила оценки Lisp определяют, что строка оценивает себя (и, следовательно, не будет интерпретироваться как выражение программы, а только как строковые данные). Число также оценивает себя. Список (грех 3.0) - это список символа и числа. Правила оценки говорят, что этот список с символом, обозначающим функцию в качестве первого объекта, будет оцениваться как приложение функции. Существует несколько таких правил оценки для данных, специальных операторов, приложений макросов и приложений функций. Вот и все.
Для ясности: в Лиспе функция EVAL определена над структурами данных Лисп * . Он ожидает структуру данных, оценивает ее в соответствии со своими правилами оценки и возвращает результат - снова используя свои структуры данных.
Это соответствует определению homoiconic: исходный код имеет нативное представление с использованием типов данных Lisp.
Теперь интересная часть такова: не имеет значения, как реализован EVAL . Все, что имеет значение, - это то, что он принимает исходный код с использованием структур данных Lisp, что он выполняет код и возвращает результат.
Так что совершенно законно, что EVAL использует компилятор .
(EVAL code) = (run (compile-expression code))
Так работает несколько систем Lisp, у некоторых даже нет Интерпретатора.
Итак, «Homoiconic» говорит, что код SOURCE имеет представление данных. Это НЕ говорит, что во время выполнения этот исходный код должен интерпретироваться или что выполнение основано на этом исходном коде.
Если код скомпилирован, во время выполнения не требуется ни компилятор, ни интерпретатор . Они понадобятся только в том случае, если программа захочет оценить или скомпилировать код во время выполнения - что часто не требуется.
Lisp также предоставляет примитивную функцию READ , которая переводит внешнее представление (S-выражения) данных во внутреннее представление данных (данные Lisp). Таким образом, его также можно использовать для перевода внешнего представления исходного кода во внутреннее представление исходного кода. Lisp не использует специальный синтаксический анализатор для исходного кода - поскольку код является данными, существует только READ.