Я буду признателен за то, что мои знания о Лиспе чрезвычайно минимальны.Однако я чрезвычайно заинтересован в языке и планирую начать серьезно изучать его в ближайшем будущем.Мое понимание этих вопросов, без сомнения, неверно, поэтому, если я скажу что-то, что явно неверно, пожалуйста, прокомментируйте и исправьте меня, а не понизьте.*
Я ищу примеры языков программирования, которые поддерживают как Homoiconicity (код имеет то же представление, что и данные), так и unrestricted self-модификация (Unrestricted, означающее, что вы можете изменять каждый аспект вашего работающего кода,не просто генерировать новый код или изменять указатели / делегаты функций.)
На данный момент я нашел только три примера, которые соответствуют этим критериям:
- Машинный код.Homoiconic в том, что все это число.Неограниченно модифицируется тем, что включает указатели, которые можно использовать для манипулирования любым адресом памяти независимо от того, содержит ли этот адрес код или данные.
- Malbolge.Те же рассуждения, что и машинный код.Каждая инструкция модифицируется после выполнения
- DNA.Не язык программирования, но все же интересно.Оно не самоизменяется в том же смысле, что и машинный код;Где фактические инструкции + данные изменены на месте.Однако он самовоспроизводится и может видоизменяться / эволюционировать в соответствии с его предыдущим состоянием (с такими побочными эффектами, как радиация, которые порой портят его).В любом случае, это всего лишь косвенный способ модификации себя.Короче говоря, ДНК может самоизменяться, но она делает это, воспроизводя себя в своей целостности вместе с соответствующими мутациями.Физическая строка ДНК является «неизменной».
Почему Лисп нет в этом списке
Лисп нет в этом списке, потому что мне кажется, чтоLisp только почти Homoiconic и поддерживает только ограниченную самодиагностику.Вы можете сделать что-то вроде
(+ 1 2 3)
, что будет делать то же самое, что и
(eval '(+ 1 2 3))
В первой версии (+ 1 2 3)
является необработанным кодом, тогда как во второй версии это данные.Предполагая истинность этого утверждения, можно утверждать, что Лисп даже не омичен.Код имеет то же представление, что и данные, в том смысле, что они оба являются списками / деревьями / S-выражениями.Но тот факт, что вы должны явно пометить, какие из этих списков / деревьев / S-выражений являются кодом, а какие являются данными для меня, похоже, говорит о том, что Lisp в конце концов не омичен.Представления чрезвычайно похожи, но они отличаются мельчайшими деталями, которые вы фактически должны сказать, имеете ли вы дело с кодом или данными.Это ни в коем случае не плохо (на самом деле все остальное было бы безумием), но оно подчеркивает разницу между Лиспом и машинным кодом.В машинном коде вам не нужно явно отмечать, какие числа являются инструкциями, какие указатели, а какие данные.Все является просто числом, пока на самом деле не требуется интерпретация, и в этот момент это может быть любая из этих вещей.
Это еще более веский аргумент против неограниченной самодиагностики.Конечно, вы можете взять список, который представляет некоторый код и манипулировать им.Например, изменив
'(+ 1 2 3)
на
'(+ 1 4 3)
, а затем выполните его через eval
.Но когда вы делаете это, вы просто компилируете некоторый код и запускаете его.Вы не модифицируете существующий код, вы просто создаете и запускаете новый код.C # может делать то же самое, используя деревья выражений, даже если в менее удобном формате (что возникает из-за того, что код C # имеет другое представление для своего AST, в отличие от Lisp, который является его собственным AST),Можете ли вы взять весь исходный файл и начать изменять весь этот исходный файл во время его работы, при этом изменения, внесенные в исходный файл, влияют на поведение программы в реальном времени?
Если нет какого-либо способа сделать это, Лисп не является ни омиконическим, ни самоизменяющимся.(Чтобы отложить спор над определениями, Лисп не гомоичен и не самоизменяется до той же степени, что и машинный код. )
Способы сделать Лисп гомоиконическим / неограниченно самоограниченныммодифицируемый
Я вижу 3 возможных способа сделать Lisp гомо-звуковым / самоизменяемым как машинный код.
- Архитектура не фон Неймана. Если кто-то может изобрести какую-то удивительную гипотетическую машину, где представление программ самого низкого уровня - это AST, который может быть выполнен напрямую (дальнейшая компиляция не требуется).На такой машине AST будет представлять как исполняемые инструкции, так и данные.К сожалению, проблема не была решена, потому что AST все еще должен быть либо кодом, либо данными.Превосходство функции eval не меняет этого.В машинном коде вы можете переключаться между кодом и данными столько раз, сколько захотите.Принимая во внимание, что с помощью eval и Lisp, когда вы «утащили» какой-то список из данных в код и выполнили его, нет способа вернуть этот список обратно в качестве данных.Фактически, этот список исчез навсегда и был заменен его значением.Мы упустили бы что-то решающее, и именно так получились указатели.
- Ярлыки списков. Если бы требовалось, чтобы у каждого списка также был уникальный ярлык, было бы возможносделать косвенную самодиагностику, запустив функции для списка с данной меткой.В сочетании с продолжениями это, в конечном счете, позволило бы самостоятельно модифицировать код в том же смысле, в каком он есть в машинном коде.Метки соответствуют адресам памяти машинного кода.В качестве примера рассмотрим программу на Лиспе, где верхний узел AST имеет метку «main».Внутри main вы можете затем выполнить функцию, которая принимает метку, Integer, Atom и копирует атом в список с меткой, которая соответствует метке, предоставленной функции, по индексу, указанному в Integer.Тогда просто позвоните с текущим продолжением на главную.Вот, пожалуйста, самоизменяющийся код.
- Макросы Lisp. Я не нашел времени, чтобы разобраться с макросами Lisp, и на самом деле они могут делать именно то, о чем я думаю.
Точка 1. в сочетании с 2. создаст полностью самоизменяющийся Лисп.При условии, что описанная волшебная машина Лиспа может быть произведена2. один может создать самоизменяющийся Лисп, однако реализация на архитектуре фон Неймана может быть крайне неэффективной.
Вопросы
- Любыеязыки, отличные от машинного кода, днк и malbolge, которые могут выполнять полную самомодификацию и являются гомоиконическими?
- (НЕ ДУМАЙТЕ отвечать, если вы выполнили tl; dr по вышеуказанному тексту) .Действительно ли LISP гомоичны + самоизменяются?Если вы так говорите, можете ли вы процитировать точно, где в моем рассуждении я сбился с пути?
Приложение
Языки с неограниченной самодиагностикой, но без омиконичности
- Сборка.Код использует слова в отличие от чисел, поэтому теряет омиконичность, но в нем все еще есть указатели, которые сохраняют полный контроль над памятью и допускают неограниченное самостоятельное изменение.
- Любой язык, использующий необработанные указатели.Например, C / C ++ / Objective C. Тот же аргумент, что и в языках Assembly
- JIT, которые содержат виртуальные указатели.Например, C # /. Net работает в небезопасном контексте.Тот же аргумент, что и Assembly.
Другие понятия и языки, которые могут быть как-то актуальны / интересны:Lisp, Ruby, Snobol, Forth и его метапрограммирование во время компиляции, Smalltalk и его отражение, нетипизированное лямбда-исчисление с его свойством, что все является функцией (что предполагает, что мы можем изобрести машину, которая непосредственно выполняет лямбда-исчисление, лямбда-исчислениебыл бы гомоиконичным, а машинный код фон Неймана не был бы при запуске на указанной машине. [И теорема Годельса была бы исполняемой. Ха-ха, страшная мысль: P])