同质性的水平

The*_*kle 9 lisp machine-code self-modifying homoiconicity

这是我之前的问题的后续跟进.我不相信Lisp代码与Von Neumann架构上的机器代码一样是Homoiconic.对我来说似乎很明显,在这两种情况下代码都表示为数据,但似乎很明显,你可以在机器代码中比在Lisp中更自由地利用这个属性.

在使用机器代码时,自我修改代码非常容易,它总是偶然发生,通常是偶然的,并且(根据我的经验)是搞笑的结果.在编写一个简单的"打印数字0-15"程序时,我的一个指针可能会出现"off by one"错误.我最终会意外地将寄存器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
Run Code Online (Sandbox Code Playgroud)

现在我想要发生的是在这个程序中添加一些Lisp代码,它会将*更改为+,将<=更改为a> =,在那里的某处粘贴一个(+ 1 2 3),并且通常会对函数进行操作起来.然后我希望程序执行结果的绝对混乱.

关键点:除非我在示例代码中犯了一些致命错误,否则您只能更改该-– More code goes here –-部分.你在上面看到的是代码.我不希望你引用整个列表并将其存储在变量中,以便可以将其作为具有相同名称的单独函数进行操作和吐出; 我不希望将阶乘的标准重新定义视为完全不同的东西.我想要那些代码,就在那里,我可以在屏幕上看到我在眼前改变自己,就像机器代码一样.

如果这是一个不可能/不合理的请求,那么它只会在我的脑海中进一步巩固Homoiconicity不是语言有或没有的离散属性的想法,它是一个谱,而Lisp并不处于最前沿.(或者Lisp就像他们来的同性恋,我正在寻找一些其他术语来描述机器代码式的自我修改)

Rai*_*wig 16

这很简单.您只需要更改列表表示.您只需要一个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
Run Code Online (Sandbox Code Playgroud)

这是一个函数修改自身的例子.为了使它更容易一些,我使用了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
Run Code Online (Sandbox Code Playgroud)

上述功能可选择使用+*修改其代码.

#1=是表达式中的标签,#1#然后引用该标签.

CL-USER 181 > (factorial 10)
4555
Run Code Online (Sandbox Code Playgroud)

在早期(70s/80s)的一些Lisp组中,开发人员没有使用文本编辑器来编写Lisp代码,而是使用结构编辑器.编辑器命令直接改变了Lisp代码的结构.

  • 哈哈哇。棒极了。我一直在寻找像这样的东西。而且我想也没有什么可以阻止您在REPL之外进行此类操作(因此,您可能具有一个可以反复修改自身的递归函数?) (2认同)
  • @ThomasBartscher:是的.我还假设它是一个解释器 - 也是一个不可移植的东西.Common Lisp不仅涉及可移植语言,还涉及个别实现具有一定自由度(解释器与编译器,开发与交付,优化,垃圾收集......).只需选择具有正确功能集的Common Lisp实现. (2认同)