Уровни гомоиконичности
Это продолжение моего предыдущего вопроса. Я не уверен, что код на Лиспе настолько же гомоичен, как и машинный код на архитектуре фон Неймана. Мне кажется очевидным, что в обоих случаях код представляется в виде данных, но также очевидно, что вы можете использовать это свойство гораздо более свободно в машинном коде, чем в Лиспе.
При работе с машинным кодом самоизменяющийся код настолько прост, что происходит постоянно, часто случайно и с (по моему опыту) веселыми результатами. При написании простой программы "печать чисел 0-15" у меня может быть ошибка "выключено одним" с одним из моих указателей. Я закончу тем, что случайно выгружу все, что находится в Регистре 1, в адрес в памяти, который содержит следующую инструкцию, и вместо этого будет выполнена случайная инструкция. (Всегда здорово, когда это что-то вроде "goto". Бог знает, где это закончится и что он будет делать после того, как это произойдет)
Там действительно нет разделения между кодом и данными. Все это одновременно инструкция (даже если это просто NOP), указатель и просто старое число. И код может измениться на ваших глазах.
Пожалуйста, помогите мне с сценарием Lisp, который я ломал голову. Скажем, у меня есть следующая программа:
(defun factorial (n)
(if (<= n 1)
1
(* n (factorial (- n 1)))))
; -- Demonstrate the output of factorial --
; -- The part that does the Self modifying goes here –
; -- Demonstrate the changed output of factorial
Теперь я хочу добавить к этой программе некоторый код на Лиспе, который изменит * на a +, изменит <= на>>, вставит (+ 1 2 3) где-то там, и, как правило, вызовет функцию вверх. И тогда я хочу, чтобы программа выполнила полный беспорядок, который в результате.
Ключевой момент: если я не допустил фатальную ошибку в примере кода, вам разрешено только изменять -– More code goes here –-
часть. То, что вы видите выше, это код. Я не хочу, чтобы вы цитировали весь список и сохраняли его в переменной, чтобы им можно было манипулировать и выплевывать как отдельную функцию с тем же именем; Я не хочу стандартного переопределения факториала как чего-то совершенно другого. Я хочу, чтобы этот код, прямо там, который я мог видеть на своем экране, изменился перед моими глазами, точно так же, как машинный код.
Если это невыполнимый / необоснованный запрос, то он только укрепляет мою мысль о том, что гомойконичность не является дискретным свойством, которое язык имеет или не имеет, а является спектром, а Лисп не на переднем крае. (В качестве альтернативы Лисп настолько же гомоичен, насколько и они, и я ищу какой-то другой термин для описания самодиагностики в машинном коде)
1 ответ
Это легко. Вам нужно только изменить представление списка. Все, что вам нужно, это интерпретатор Lisp.
Реализация Common Lisp LispWorks предоставляет нам интерпретатор Lisp:
CL-USER 137 > (defun factorial (n)
(if (<= n 1)
1
(* n (factorial (- n 1)))))
FACTORIAL
CL-USER 138 > (fifth (function-lambda-expression #'factorial))
(IF (<= N 1) 1 (* N (FACTORIAL (- N 1))))
CL-USER 139 > (fourth (fifth (function-lambda-expression #'factorial)))
(* N (FACTORIAL (- N 1)))
CL-USER 140 > (setf (first (fourth (fifth (function-lambda-expression
#'factorial))))
'+)
+
CL-USER 141 > (fourth (fifth (function-lambda-expression #'factorial)))
(+ N (FACTORIAL (- N 1)))
CL-USER 142 > (factorial 10)
55
CL-USER 143 > (setf (first (fourth (fifth (function-lambda-expression
#'factorial))))
'*)
*
CL-USER 144 > (factorial 10)
3628800
Вот пример, где функция модифицирует себя. Чтобы сделать это немного проще, я использую функцию Common Lisp: она позволяет мне писать код, который представляет собой не просто вложенный список, а график. В этом случае функция может получить доступ к своему собственному коду:
CL-USER 180 > (defun factorial (n)
(if (<= n 1)
1
(progn
(setf (first '#1=(* n (factorial (- n 1))))
(case (first '#1#)
(+ '*)
(* '+)))
#1#)))
FACTORIAL
Выше функции альтернативно использует +
или же *
изменив его код.
#1=
является меткой в выражении, #1#
затем ссылается на этот ярлык.
CL-USER 181 > (factorial 10)
4555
В более ранние времена (70-е /80-е) в некоторых группах Lisp разработчики использовали не текстовый редактор для написания кода на Lisp, а структурный редактор. Команды редактора напрямую меняли структуру кода на Лиспе.