The*_*kle 29 lisp assembly machine-code self-modifying homoiconicity
我将继续承认我对Lisp的了解非常少.但是我对这门语言非常感兴趣,并计划在不久的将来开始认真学习它.我对这些问题的理解无疑是有缺陷的,所以如果我说出任何错误的内容,请评论并纠正我而不是贬低.
真正的同性恋和自我修改的语言
我正在寻找支持Homoiconicity(代码与数据表示相同)和不受限制的自我修改的编程语言示例(Unrestricted意味着您可以更改正在运行的代码的每个方面,而不仅仅是发出新代码或更改函数指针/代表).
到目前为止我发现的三个例子符合这个标准:
为什么Lisp不在此列表中
Lisp不在那个列表中,因为在我看来,Lisp 几乎只是Homoiconic,并且只支持受限制的自我修改.你可以做点什么
(+ 1 2 3)
Run Code Online (Sandbox Code Playgroud)
这将做同样的事情
(eval '(+ 1 2 3))
Run Code Online (Sandbox Code Playgroud)
第一个版本(+ 1 2 3)是原始代码,而第二个版本是数据.通过假设这个陈述的真实性,可以说Lisp甚至不是杀人的.代码与数据具有相同的表示形式,即它们都是列表/树/ S表达式.但事实上你必须明确地标记这些列表/树/ S表达式中的哪些是代码以及哪些是我的数据似乎说Lisp毕竟不是杀人的.这些表示非常相似,但它们的细节不同,您必须实际说明您是在处理代码还是数据.这绝不是一件坏事(实际上其他任何东西都会是疯狂的),但它强调了Lisp和机器代码之间的区别.在机器代码中,您不必明确标记哪些数字是指令,哪些是指针,哪些是数据.在实际需要解释之前,一切都只是一个数字,此时它可以是任何一个.
对于不受限制的自我修改,这是一个更强大的案例.当然,您可以获取代表某些代码并对其进行操作的列表.例如改变
'(+ 1 2 3)
Run Code Online (Sandbox Code Playgroud)
至
'(+ 1 4 3)
Run Code Online (Sandbox Code Playgroud)
然后你运行它eval.但是当你这样做时,你只是编译一些代码并运行它.您没有修改现有代码,只是发出并运行新代码.C#可以使用表达式树完全相同的事情,即使是一种不太方便的格式(由于C#代码对其AST具有不同的表示而产生,而不是Lisp,这是它自己的AST).您是否可以实际获取整个源文件并在运行时开始修改整个源文件,对源文件所做的更改会对程序行为产生实时影响?
除非有某种方法可以做到这一点,否则Lisp既不是讽刺也不是自我修改.(为了推断定义的争论,Lisp不是同源的,也不是自我修改到与机器代码相同的程度.)
如何制作Lisp Homoiconic/Unrestrictedly self-modifiable
我可以看到3种可能的方法使Lisp像机器代码一样可以单调/自我修改.
点1.结合2.将产生一个完全自我修改的Lisp.前提是可以生产所描述的神奇的Lisp机器.2.单独可以产生自我修改的Lisp,但是在冯·诺依曼架构上的实现可能非常低效.
问题
附录
语言具有不受限制的自我修改但不具有杀戮性
其他概念和语言可能在某种程度上相关/有趣:Lisp,Ruby,Snobol,Forth和它的编译时元编程,Smalltalk和它的反射,无类型的lambda演算,它的属性是一切都是函数(哪种意味着假设我们可以发明一台直接执行lambda演算的机器,lambda演算将是homoiconic而Von Neumann机器代码在所述机器上运行时不会.[并且Godels定理将是可执行的.哈哈,可怕的想法:P])
Fre*_*Foo 20
第一个版本
(+ 1 2 3)是原始代码,而第二个版本是数据.通过假设这个陈述的真实性,可以说Lisp甚至不是杀人的.代码与数据具有相同的表示形式,即它们都是列表/树/ S表达式.但事实上你必须明确地标记这些列表/树/ S表达式中的哪些是代码以及哪些是我的数据似乎说Lisp毕竟不是杀人的.
这不是真的.在第一个版本中,作为(+ 1 2 3)数据的列表被馈送到要执行的解释器,即被解释为代码.您必须将s表达式标记为特定上下文中的代码或数据这一事实不会使Lisp成为非同构的.
同质性的观点是所有程序都是数据,而不是所有数据都是程序,因此两者之间仍然存在差异.在Lisp中,(1 2 3)是一个有效的列表,但不是一个有效的程序,因为整数不是一个函数.
[如果我们看一下另一个伟大的homoiconic编程语言Prolog,那么我们就会看到同样的现象:我们可以构建一个数据结构foo(X, 1, bar),但是如果没有定义foo,我们就无法执行它.此外,变量不能是谓词或事实的名称,因此X.永远不是有效的程序.]
Lisp在很大程度上是自我修改的.例如,以下是如何更改函数的定义:
[1]> (defun foo (x) (+ x 1))
FOO
[2]> (defun bar (x) (+ x 2))
BAR
[3]> (setf (symbol-function 'foo) #'bar)
#<FUNCTION BAR (X) (DECLARE (SYSTEM::IN-DEFUN BAR)) (BLOCK BAR (+ X 2))>
[4]> (foo 3)
5
Run Code Online (Sandbox Code Playgroud)
说明:at [1],我们将函数定义foo为add-1函数.在[2],我们定义bar为add-2函数.在[3],我们重置foo为add-2功能.在[4],我们看到我们已成功修改foo.
Rai*_*wig 12
Lisp是一系列编程语言.这个家庭的成员在能力和实施技术上有很大的不同.对此有两种不同的解释:
Lisp是一个共享一些重叠功能集的语言系列.这包括从第一个Lisp到Maclisp,Scheme,Logo,Common Lisp,Clojure以及数百种不同语言及其实现的所有内容.
Lisp还有一个主要的语言分支,它们的名字中也大多数都有'Lisp':Lisp,MacLisp,Common Lisp,Emacs Lisp,......
随着时间的推移,已经投入了大量的研究来改进语言(使其更具"功能性"或使其更加面向对象,或两者兼而有之)并改进实现技术.
例如,Common Lisp支持编译,各种优化等,允许开发人员在需要在灵活性和功能之间取得平衡的大型项目中使用它.编译后的函数就是机器代码,不再是由列表,符号,字符串和数字组成的数据结构.
Common Lisp允许实现创建静态代码.同时,它为受控运行时修改留下了一些空间(例如,通过使用运行时编译器,加载代码,评估代码,替换代码,......).
OTOH如果你有一个带解释器的Lisp实现,另外解释器可能使用Lisp数据结构来表示源,那么你就可以改变运行程序,例如通过改变列表结构.有Lisp方言的实现允许这样做.一个典型的事情是使用宏,这些宏可以在运行时由这样的系统计算.其他一些Lisps有所谓的Fexprs,它们是一种类似的机制(但通常无法有效编译).
在基于Common Lisp的应用程序(例如,用Lisp编写的CAD系统)中,许多源信息已被传送工具删除,这是不可能的.人们可以拥有一个机器代码的可执行文件,它可以消除大部分的运行时灵活性.
同质性也不是一个非常明确的概念.对于Lisp我更喜欢我们说源代码可以转换成数据,因为源代码使用s表达式的外部表示,这是一种数据序列化格式.但并非每个s表达式都是有效的Lisp程序.此外,作为Lisp数据的源代码的内部表示在任何方面都不是"标志性的".Lisp将源代码作为外部s表达式,在阅读源代码后,它具有Lisp数据的内部表示.READ读取它,PRINT打印它,EVAL评估它.
在Lisp中还有其他方法可以提供对运行程序和程序的Lisp的访问:
CLOS中的元对象协议(Common Lisp Object System)就是这样一个例子
3Lisp提供了无限的解释塔.有一个运行程序的Lisp解释器.这个Lisp解释器是由另一个Lisp解释器运行的,它又在另一个解析器中运行,那个也是......
| 归档时间: |
|
| 查看次数: |
5237 次 |
| 最近记录: |