Может ли компилируемый язык быть гомойным? - PullRequest
27 голосов
/ 06 августа 2009

По определению слово homoiconic означает:

То же представление кода и данных

В LISP это означает, что вы можете иметь список в кавычках и оценивать его, поэтому (car list) будет функцией и (cdr list) аргументами. Это может произойти как во время компиляции, так и во время выполнения, однако для этого требуется интерпретатор.

Возможно ли, что скомпилированные языки без интерпретатора времени компиляции также могут быть гомоиконическими? Или понятие гомойконичности ограничено интерпретаторами?

Ответы [ 10 ]

35 голосов
/ 06 августа 2009

«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.

8 голосов
/ 06 августа 2009

да. lisp может быть скомпилирован в собственный двоичный файл

3 голосов
/ 06 августа 2009

Мне кажется странным вопрос:

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

Точка машинного кода DSM является хорошей точкой, но она обеспечивает:

  1. Представленный синтаксис и семантика гомоичны
  2. Перевод на форму более низкого уровня (машинный код или интерпретированный или иным образом) не удаляет никакой оригинальной семантики тогда

почему реализация нижнего уровня имеет значение здесь?

Также:

скомпилированные языки без интерпретатора времени компиляции

Без какой-либо программы, которая его интерпретирует, она должна была бы быть родной для ЦП, поэтому родной язык ЦП должен был бы быть гомоиконичным (или виртуальной машиной, выполняющей код).

Языки без интерпретации во время компиляции ... будут довольно ограничены ... так как они не будут компилироваться вообще .

Но я не эксперт, и, возможно, упускаю суть.

2 голосов
/ 10 сентября 2009

Сам машинный код гомоичен, так что да.

Данные или инструкции являются лишь вопросом семантики (и, возможно, сегмента памяти, в которой они находятся).

2 голосов
/ 07 августа 2009

Lisp обычно компилируется. Были реализации с JIT-компиляторами вместо интерпретаторов.

Следовательно, нет необходимости иметь интерпретатор (в смысле «не компилятор») для языков кода-данных.

2 голосов
/ 06 августа 2009

В самой буквальной форме C гомоичен. Вы можете получить доступ к представлению функции с помощью &functionName и выполнить данные с помощью somePtrCastToFnPtr(SomeArgs). Однако это на уровне машинного кода, и без какой-либо поддержки библиотеки вам будет очень сложно работать. Какой-то встраиваемый компилятор (кажется, я помню, что LLVM может сделать это) сделает его более практичным.

1 голос
/ 04 мая 2012

Компиляция - это просто оптимизированная интерпретация. Интерпретатор берет часть данных, представляющих код, а затем «делает» этот код: значение кода превращается в пути выполнения и поток данных через кишки интерпретатора. Компилятор берет те же данные, переводит их в другую форму и затем передает их другому интерпретатору: реализованному в кремнии (ЦП) или, возможно, в поддельной (виртуальная машина).

Вот почему некоторые реализации Lisp могут не иметь интерпретаторов. Функция EVAL может скомпилировать код и затем перейти к нему. EVAL и COMPILE не обязательно должны иметь разные режимы работы. (Clozure, Corman Lisp, SBCL являются примерами Lisps "только для компилятора".)

Часть данных в начале является ключом к тому, что язык гомоичен, независимо от того, оптимизировано ли выполнение кода путем компиляции. «Код - данные» означает « источник код - данные», а не «исполняемый код - данные». (Конечно, исполняемый код - это данные, но под данными мы подразумеваем подавляющее большинство предпочтительного представления кода, которым мы хотим манипулировать.)

1 голос
/ 07 августа 2009

Да; вам просто нужно вставить копию компилятора в языковую среду выполнения. Chez Scheme - один из многих хороших компиляторов, которые делают именно это.

1 голос
/ 06 августа 2009

Проблема заключается в том, что многие процессоры разделяют области команд и данных и активно не позволяют программам изменять свой собственный код. Этот вид кода раньше назывался «вырожденным кодом» и считался очень плохой вещью.

У интерпретаторов (и виртуальных машин) такой проблемы нет, поскольку они могут обрабатывать всю программу как данные, а интерпретатором является только «код».

0 голосов
/ 06 августа 2009

Языки, построенные на основе виртуальных машин (.net clr, jre ect), могут использовать передовые технологии, которые позволяют генерировать код на лету. Одним из них является ткачество IL. Хотя он не так ясен, как eval из ECMAScript / Lisp / Scheme, но в некоторой степени может имитировать такое поведение.

Для примеров проверьте Castle DynamicProxy и для более интерактивного примера проверьте LinqPAD, F # Interactive, Scala Interactive.

...