Различие между интерпретируемым и скомпилированным кодом, вероятно, является фикцией, как подчеркивается в комментарии Рафаэля :
the claim seems to be trivially wrong without further assumptions: if there is
an interpreter, I can always bundle interpreter and code in one executable ...
Дело в том, что код всегда интерпретируется программным обеспечением, аппаратным обеспечением или их комбинацией, и процесс компиляции не может определить, каким он будет.
То, что вы воспринимаете как компиляцию, - это процесс перевода с одного языка (для источника) на другой язык T (для цели). И, интерпретатор для S , как правило , отличается от переводчика для T .STST
Скомпилированная программа переводится из одной синтаксической формы в другую синтаксическую форму P T , так что, учитывая предполагаемую семантику языков S и T , P S и P T имеют одинаковое вычислительное поведение, вплоть до нескольких вещей, которые вы обычно пытаются изменить, возможно, оптимизировать, например, сложность или простую эффективность (время, пространство, поверхность, потребление энергии). Я стараюсь не говорить о функциональной эквивалентности, поскольку это потребовало бы точных определений.PSPTSTPSPT
Некоторые компиляторы фактически использовались просто для уменьшения размера кода, а не для «улучшения» исполнения. Это имело место для языка, используемого в системе Платона (хотя они не называли это компиляцией).
Вы можете рассмотреть ваш код полностью составлен , если после процесса компиляции, вам больше не нужен переводчик для . По крайней мере, это единственный способ, которым я могу прочитать ваш вопрос, как технический, а не теоретический вопрос (поскольку, теоретически, я всегда могу перестроить переводчика).S
Afaik, одна вещь, которая может создать проблему, это мета-цикличность . То есть, когда программа будет манипулировать синтаксическими структурами на своем собственном языке , создавая фрагмент программы, который затем интерпретируется так, как если бы он был частью исходной программы. Поскольку вы можете создавать произвольные фрагменты программы на языке S в результате произвольных вычислений, манипулирующих бессмысленными синтаксическими фрагментами, я думаю, вы можете сделать почти невозможным (с инженерной точки зрения) компиляцию программы в язык T , так что теперь генерировать фрагменты Т . Следовательно, потребуется интерпретатор для S или, по крайней мере, компилятор из S вSSTTSS дляоперативной компиляциисгенерированных фрагментов в S (см. Такжеэтот документ).TS
Но я не уверен, как это можно правильно оформить (и сейчас у меня нет на это времени). И невозможно это большое слово для вопроса, который не формализован.
Дальнейшие замечания
Добавлено через 36 часов. Вы можете пропустить это очень долгое продолжение.
Многочисленные комментарии к этому вопросу показывают два взгляда на проблему: теоретический взгляд, который рассматривает ее как бессмысленный, и инженерный взгляд, который, к сожалению, не так легко формализовать.
Есть много способов взглянуть на интерпретацию и компиляцию, и я постараюсь сделать несколько набросков. Я постараюсь быть настолько неформальным, насколько я могу управлять
Схема надгробия
Одной из ранних формализаций (с начала 1960-х до конца 1990-х годов) являются диаграммы T или
Tombstone . Эти диаграммы представлены в виде компонуемых графических элементов, языка реализации интерпретатора или компилятора, исходного языка, который интерпретируется или компилируется, и целевого языка в случае компиляторов. Более сложные версии могут добавлять атрибуты. Эти графические представления можно рассматривать как аксиомы, правила вывода, которые можно использовать для механического получения генерации процессоров из доказательства их существования по аксиомам, как Карри-Ховард (хотя я не уверен, что это было сделано в шестидесятых годах :).
Частичная оценка
Другой интересный взгляд - это парадигма частичной оценки . Я просто рассматриваю программы как своего рода реализацию функций, которая вычисляет ответ с учетом некоторых входных данных. Затем интерпретатор
для языка S представляет собой программу, взять программу р S ,
написанный на S и данных D для этой программы, и вычисляет результат в соответствии с семантикой S . Частичная оценка представляет собой метод , специализирующуюся программу двух аргументов 1 и 2 , когда только один аргумент, скажем , с 1ISSpSSdSa1a2a1, известен. Намерение состоит в том, чтобы иметь более быструю оценку, когда вы, наконец, получите второй аргумент . Это особенно полезно , если 2 изменяется чаще , чем в 1 , как стоимость частичной оценки с более 1 может быть амортизируется всех вычислений , где только 2 меняется.a2a2a1a1a2
Это частая ситуация при разработке алгоритмов (часто это тема первого комментария к SE-CS), когда некоторая более статическая часть данных предварительно обрабатывается, так что стоимость предварительной обработки может быть амортизирована во всех приложениях. алгоритма с более переменными частями входных данных.
Это также является самой ситуацией интерпретаторов, так как первый аргумент - это программа, которая должна быть выполнена, и обычно выполняется много раз с разными данными (или имеет части, выполненные много раз с разными данными). Следовательно, стало естественной идеей специализировать интерпретатора для более быстрой оценки данной программы, частично оценивая его в этой программе в качестве первого аргумента. Это можно рассматривать как способ компиляции программы, и была проведена значительная исследовательская работа по компиляции путем частичной оценки интерпретатора по его первому (программному) аргументу.
Теорема Smn
Приятный момент в подходе частичной оценки состоит в том, что он берет свои корни в теории (хотя теория может быть лжецом), особенно в
теореме Клини о Смне . Я пытаюсь дать интуитивное представление об этом, надеясь, что это не расстроит чисто теоретиков.
С учетом нумерации Гёделя рекурсивных функций вы можете рассматривать φ как свое аппаратное обеспечение, так что с учетом числа Геделя p
(считывание объектного кода ) программы φ p является функцией, определенной как p (то есть вычисляемой объектным кодом на вашем оборудовании ).φφpφpp
В простейшем виде теорема изложена в википедии следующим образом (с небольшим изменением в обозначениях):
При заданной нумерации Гёделя рекурсивных функций существует примитивная рекурсивная функция σ двух аргументов со следующим свойством: для каждого числа Гёделя q частично вычислимой функции f с двумя аргументами выражения φ σ ( q , x ) ( y ) и f ( x , y ) определены для одинаковых комбинаций натуральных чисел x и y , и их значения равны для любой такой комбинации. Другими словами, следующее экстенсиональное равенство функций выполняется для каждогоφσQеφσ( д, Х )( у)е( х , у)ИксY :
Иксφσ( д, Х )≃ А , у, φQ( х , у) .
Теперь, взяв в качестве интерпретатора I S , x в качестве исходного кода программы p S и y в качестве данных d для этой программы, мы можем написать:
QяSИкспSYdφσ( ЯS, рS)≃ А , д, φяS( рS, д) .
может рассматриваться как выполнение интерпретатора I S
на аппаратных средств, то есть, как черный ящикготов интерпретировать программынаписанные на языке S .φяSяSS
Функция может рассматриваться как функция, которая специализирует интерпретатор I S для программы P S , как при частичной оценке. Таким образом, число Геделя σ ( я S , р S ) можно видеть , имеет объектный код , который скомпилированная версия программы р S .σяSпSσ( ЯS, рS)пS
Так что функция можно рассматривать как функцию, которая принимает в качестве аргумента исходный код программы q S,
написанный на языке S , и возвращает версию объектного кода для этой программы. Таким образом, C S - это то, что обычно называется компилятор.СS= λ qS, σ( ( ЯS, дS)QSSСS
Некоторые выводы
σQSяS
Формализация более ограничительного представления о том, что такое компилятор, потребует более тонкого теоретического подхода. Я не знаю, что могло быть сделано в этом направлении. Самая реальная работа по частичной оценке более реалистична с инженерной точки зрения. И, конечно же, существуют другие методы написания компиляторов, включая извлечение программ из доказательства их спецификации, разработанные в контексте теории типов, основанные на изоморфизме Карри-Ховарда (но я выхожу за пределы своей компетенции) ,
Моя цель здесь состояла в том, чтобы показать, что замечание Рафаэля не "сумасшедшее", а разумное напоминание о том, что вещи не очевидны и даже не просты. Сказать, что что-то невозможно, является сильным утверждением, которое требует точных определений и доказательств, хотя бы для того, чтобы иметь точное понимание того, как и почему это невозможно . Но построение правильной формализации для выражения такого доказательства может быть довольно трудным.
При этом, даже если конкретная функция не компилируется, в смысле, понятном инженерам, стандартные методы компиляции всегда могут быть применены к частям программ, которые не используют такую функцию, как отмечено в ответе Жиля.
Следуя ключевым замечаниям Жиля, что в зависимости от языка некоторые вещи могут быть выполнены во время компиляции, в то время как другие должны выполняться во время выполнения, что требует специального кода, мы можем видеть, что концепция компиляции на самом деле плохо определен и, вероятно, не может быть определен каким-либо удовлетворительным образом. Компиляция - это всего лишь процесс оптимизации, как я пытался показать в разделе частичной оценки , когда сравнивал его с предварительной обработкой статических данных в некоторых алгоритмах.
Как сложный процесс оптимизации, концепция компиляции фактически принадлежит континууму. В зависимости от характеристик языка или программы, некоторая информация может быть доступна статически и позволяет оптимизировать ее. Другие вещи должны быть отложены на время выполнения. Когда все становится действительно плохо, все должно быть сделано во время выполнения, по крайней мере, для некоторых частей программы, и объединение исходного кода с интерпретатором - это все, что вы можете сделать. Так что это связывание - только нижняя часть этого континуума компиляции. Большая часть исследований компиляторов посвящена поиску способов делать статически то, что раньше делалось динамически. Сборка мусора во время компиляции кажется хорошим примером.
Обратите внимание, что утверждение о том, что процесс компиляции должен генерировать машинный код, не поможет. Это именно то, что может сделать пакетирование, поскольку интерпретатор - это машинный код (ну, с кросс-компиляцией все может быть немного сложнее).