Homoiconic和"无限制的"自修改code +是真的口齿不清自我修改? [英] Homoiconic and "unrestricted" self modifying code + Is lisp really self modifying?

查看:255
本文介绍了Homoiconic和"无限制的"自修改code +是真的口齿不清自我修改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我会向前admiting我Lisp的知识是非常微乎其微。但是我在语言非常感兴趣,并打算开始认真学习它在不久的将来。我对这些问题的理解是毫无疑问的缺陷,所以如果我说什么这是blatently错误,请评论和指正,而不是downvoting。

真正Homoiconic和自我修改的语言

我在寻找它同时支持同像性编程语言的例子(code具有相同的重presentation数据)和不受限制自修改(无限制的含义,你可以改变你的跑步code的每一个环节,不仅散发出新的code或变化的函数指针/委托。)

有,但三个例子到目前为止,我还发现了符合这一标准:


  1. 机器code。 Homoiconic在于一切是一个数字。无限制修改在于它包括指针,其可以用于操作任何存储器地址而不管该地址是否持有code或内容

  2. Malbolge。理由同机code。每条指令执行后自行修改

  3. 的DNA。不是一种编程语言,但仍有趣。这是不是在同一个意义上的机器code是自修改;凡实际指令+数据的地方被修改。然而,它是自我复制和变异可/根据它的previous状态(有副作用,如辐射拧起来飘飞)发展。这只是自我修正的一种间接的方式呢。总之,DNA可自行修改,但它在它的条款内容以及相关的突变自我复制这样做。 DNA的物理字符串是不可改变的。

为什么Lisp是不在此列表中

Lisp是则不在此列,因为它在我看来,Lisp是唯一的几乎的Homoiconic,并且只支持有限的自我修正。你可以不喜欢

 (+ 1 2 3)

这将做同样的事情。

 (EVAL'(+ 1 2 3))

在第一个版本(+ 1 2 3)是原code,而在第二个版本是数据。假设这句话的真理,可以争辩说,Lisp的甚至不是homiconic。在code具有相同的重presentation在这个意义上,他们都是列出/株/ S-EX pressions数据。但事实证明,你必须明确标明这些列表/树/ S-EX pressions是code,哪些数据对我来说似乎是说,Lisp是不是homiconic毕竟。重新presentations极为相似,但它们在小小的细节上不同,你必须居然说无论你正在处理code或数据。这是不以任何方式坏事(其实什么都将是疯狂),但它强调Lisp和机code之间的差异。在机器code你没有明确标明哪些号码的说明,这是指针,它们是数据。一切仅仅是实际需要数量,直到一个跨pretation,此时它可以是任何的那些东西。

这是对自我无限制修改一个更强大的情况下。当然,你可以采取重新presents一些code列表,并操纵它。例如更改

 '(+ 1 2 3)

 '(+ 1 4 3)

然后你通过评估运行。但是,当你这样做,你只是一些编译code和运行它。你不修改现有的code,你只是发射并运行新的code。 C#中可以使用前pression树做同样的事情,即使在一个不太方便的格式(其产生是由于具有不同的重新presentation其AST C#code,而不是Lisp的,这的的自己的AST)。实际上,你可以采取一个完整的源文件,并开始修改,因为它正在运行的整个源文件,以改变为具有对程序行为的实时效果的源文件的?

除非有一些方法来做到这一点,Lisp是既不homiconic也不是自我修改。 (推迟了定义参数,Lisp是不是homoiconic或自我修改的同样程度整机code为。的)

如何使Lisp的Homoiconic /无限制地自我修改

我可以看到3潜在的方式,使Lisp语言为homoiconic /自修改为机code。


  1. 非冯·诺依曼架构。如果有人能发明一些惊人的假设的机器,其中的程序的最低水平再presentation是可以直接执行的AST(没有进一步的编辑是必要的)。在这样的机器一个AST将重新present两个可执行指令,以及数据。不幸的是,问题不会被解决,因为AST仍,必须为code或数据。一个eval函数的prescence不会改变这一点。在机器code可以来回翻动code和数据之间多达你想要的。而与EVAL和Lisp一旦你evaled从数据到code一些名单和执行的时候,有没有办法让这个列表回数据一次。事实上,该名单已经一去不复返了,并已替换为它的价值。我们很缺少的东西是至关重要的,这恰好是指针。

  2. 列表标签。如果这是一个要求,即每个列表也有一个独特的标签,这将有可能运行的功能对一个给定的标签列表做间接的自我修正。与延续,这将最终允许在同一意义上,机器code有它自修改code的组合。标签是equivilant机器code内存地址。作为一个例子,考虑一个Lisp程序,其中AST的顶级节点的标签是主。在main然后你可以执行一个函数,一个标签,一个整数,一个原子,并复制原子的列表与匹配提供给函数的一个标签,由整数指定的索引处。然后,只需用当前的主要延续调用。你去那里,自我修改code。

  3. Lisp的宏。我还没有花时间去了解Lisp的宏,他们可能实际上做的正是我在想。

1点与2相结合将产生一个完全自修改Lisp的。但所描述的神奇的Lisp机器可以生产。 2.能够单独产生于冯·诺依曼架构的自修改Lisp的,但是实施可能极为innefficient。

的问题


  1. 是不是机器code,DNA和malbolge它可以做自我总量修改和是homoiconic其他任何语言?

  2. (不打扰,如果你做了回答TL;博士在上面的文字)。是真的口齿不清+ homoiconic自我修改?如果你这么说,你可以准确地报价凡在我的说法我误入歧途?

附录

无限制的自我修正,但没有homiconicity

语言

  1. 大会。的code使用词语,而不是数字,所以失去homiconicity,但它仍然有指针,它保留了完全控制存储器,并允许无限制自修饰。

  2. 使用原始指针任何语言。例如C / C ++ /目标C.相同的参数作为大会

  3. JIT种语言,包括虚拟指针。例如C#/。在不安全的情况下净投放。同样的论点作为大会。

其它的概念和语言,可能以某种方式相关的/有趣的:
口齿不清,红宝石,SNOBOL,第四,它的编译时元编程,Smalltalk和它的倒影,它无类型演算的财产,一切是一个函数(哪一种暗示假设我们可以发明一种机器,直接执行演算,演算将homoiconic和冯诺依曼机code将不会运行时,该机械[和Godels定理是可执行哈哈,可怕的想法:p]。)


解决方案

  

在第一个版本(+ 1 2 3)是原code,而在第二个版本是数据。假设这句话的真理,可以争辩说,Lisp的甚至不是homiconic。在code具有相同的重presentation在这个意义上,他们都是列出/株/ S-EX pressions数据。但事实证明,你必须明确标明这些列表/树/ S-EX pressions是code,哪些数据对我来说似乎是说,Lisp是不是homiconic毕竟。


这是不正确的。在第一个版本,名单(+ 1 2 3),这是数据,被送入间preTER被执行,即是间preTED为code 的。你必须标记S-EX pressions作为是code或在一个特定的上下文数据的事实上的不作Lisp的非homoiconic。

同像性的一点是,所有的程序都数据,而不是所有的数据都是程序,所以仍存在两者之间的差别。在Lisp中,(1 2 3)是一个有效的列表,但不是一个有效的程序,因为一个整数是不是一个函数。

[如果我们看一下其他伟大homoiconic编程语言Prolog中,我们看到了同样的现象:我们可以建立一个数据结构美孚(X,1,吧),但没有的定义,我们不能执行它。此外,变量不能是predicates或事实的名字,所以 X 从来都不是一个有效的程序。]

Lisp是自修改在很大程度上。例如,这里是如何改变一个函数的定义:

  [1] GT; (defun函数富(X)(+×1))
FOO
[2]≥ (defun函数巴(X)(+ X 2))
酒吧
[3]≥ (SETF(符号功能'富)#栏)
#<作用BAR(X)(DECLARE(系统:IN-defun函数BAR))(BLOCK BAR(+ X 2))>
[4]≥ (富3)

说明:在 [1] ,我们定义函数是附加功能1。在 [2] ,我们定义了是附加功能2。在 [3] ,我们将重置来加载2的功能。在 [4] ,我们可以看到,我们已经成功地修改

I will be forward in admiting that my knowledge of Lisp is extremely minimal. However I am extremely interested in the language and plan to begin seriously learning it in the near future. My understanding of these issues is no doubt flawed, so if I say anything which is blatently wrong, please comment and correct me rather than downvoting.

Truly Homoiconic and Self-modifiable languages

I'm looking for examples of programming languages which support both Homoiconicity (Code has the same representation as data) and unrestricted self modification (Unrestricted meaning that you can change every aspect of your running code, not merely emit new code or change function pointers/delegates.)

There are but three examples I have found so far which fit this criteria:

  1. Machine code. Homoiconic in that everything is a number. Unrestrictedly modifiable in that it includes pointers, which can be used to manipulate any memory address regardless of whether that address holds code or data.
  2. Malbolge. Same reasoning as Machine code. Every instruction modifies itself after being executed
  3. DNA. Not a programming language, but still interesting. It isn't self modifying in the same sense as machine code is; Where the actual instructions + data are modified in place. However it is self replicating and can mutate/evolve according to it's previous state (With side effects such as radiation screwing it up every now and then). This is just an indirect way of self modification anyway. In short, DNA can self modify, but it does so by reproducing itself in it's entirity along with the relevant mutations. A physical string of DNA is "immutable".

Why Lisp is not on this list

Lisp is not on that list because it appears to me that Lisp is only almost Homoiconic, and only supports restricted self modification. You can do something like

(+ 1 2 3)

which will do the same thing as

(eval '(+ 1 2 3))

In the first version (+ 1 2 3) is raw code, whereas in the second version it is data. By assuming the truth of this statement it can be argued that Lisp isn't even homiconic. The code has the same representation as data in the sense that they are both lists/trees/S-expressions. But the fact that you have to explicitly mark which of these lists/trees/S-expressions are code and which are data to me seems to say that Lisp is not homiconic after all. The representations are extremely similar, but they differ in the tiny detail that you have to actually say whether you are dealing with code or data. This is not in any way a bad thing (In fact anything else would be madness), but it highlights a difference between Lisp and machine code. In machine code you don't have to explicitly mark which numbers are instructions, which are pointers, and which are data. Everything is simply a number until an interpretation is actually required, at which point it could be any of those things.

It's an even stronger case against unrestricted self modification. Sure, you can take a list that represents some code and manipulate it. For example changing

'(+ 1 2 3)

to

'(+ 1 4 3)

And then you run it through eval. But when you do this you're just compiling some code and running it. You're not modifying existing code, you're just emitting and running new code. C# can do exactly the same thing using expression trees, even if in a less convenient format (which arises due to C# code having a different representation to its AST, as opposed to Lisp, which is its own AST). Can you actually take an entire source file and start modifying that entire source file as it is running, with the changes made to the source file having realtime effects on the program behaviour?

Unless there is some way to do this, Lisp is neither homiconic nor self modifying. (To put off an argument over definitions, Lisp is not homoiconic or self modifying to the same degree that machine code is.)

Ways to make Lisp Homoiconic/Unrestrictedly self-modifiable

I can see 3 potential ways to make Lisp as homoiconic/self-modifiable as machine code.

  1. Non-Von-Neumann architecture. If someone could invent some amazing hypothetical machine where the lowest level representation of programs is an AST which can be executed directly (No further compilation is necessary). On such a machine an AST would represent both executable instructions, as well as data. Unfortunately the problem won't have been solved, because the AST still has to be either code or data. The prescence of an eval function doesn't change this. In machine code you can flip back and forth between code and data as much as you want. Whereas with eval and Lisp once you've "evaled" some list from data to code and executed it, there's no way to get that list back as data again. In fact, that list is gone forever and has been replaced with it's value. We'd be missing something crucial, which just so happens to be pointers.
  2. List Labels. If it was a requirement that every list also have a unique label, it would be possible to do indirect self modification by running functions against a list with a given label. Combined with continuations this would finally allow for self modifying code in the same sense that machine code has it. The labels are equivilant to machine code memory addresses. As an example, consider a Lisp program where the top node of the AST has the label "main". Inside main you could then execute a function that takes a label, an Integer, an Atom, and copies the atom to the List with a label that matches the one supplied to the function, at the index specified by the Integer. Then just call with current continuation on main. There you go, self modifying code.
  3. Lisp Macros. I haven't taken the time to understand Lisp macros, and they may in fact do exactly what I'm thinking about.

Point 1. combined with 2. would produce a totally self-modifying Lisp. Provided that the magical Lisp machine described could be produced. 2. alone could produce a self-modifying Lisp, however the implementation on a Von Neumann architecture could be extremely innefficient.

The Questions

  1. Are the any languages other than machine code, dna and malbolge which can do total self modification and are homoiconic?
  2. (DO NOT bother answering if you did a tl;dr at the above text). Is lisp really homoiconic + self modifying? If you say so, can you quote exactly where in my argument I went astray?

Appendix

Languages with unrestricted self modification but no homiconicity

  1. Assembly. The code uses words as opposed to numbers, so loses homiconicity, but it still has pointers, which retains the total control over memory and allows for unrestricted self modification.
  2. Any language that uses raw pointers. For example C/C++/Objective C. Same argument as Assembly
  3. JIT languages that include virtual pointers. For example C#/.net running in an unsafe context. Same argument as Assembly.

Other concepts and languages that may be somehow relevant/interesting: Lisp, Ruby, Snobol, Forth and it's compile time metaprogramming, Smalltalk and it's reflection, the untyped lambda calculus with it's property that everything is a function (Which kind of implies that assuming we could invent a machine which executes lambda calculus directly, lambda calculus would be homoiconic and Von Neumann machine code would not when run on said machine. [And Godels theorem would be executable. Haha, scary thought :P])

解决方案

In the first version (+ 1 2 3) is raw code, whereas in the second version it is data. By assuming the truth of this statement it can be argued that Lisp isn't even homiconic. The code has the same representation as data in the sense that they are both lists/trees/S-expressions. But the fact that you have to explicitly mark which of these lists/trees/S-expressions are code and which are data to me seems to say that Lisp is not homiconic after all.

This is not true. In the first version, the list (+ 1 2 3), which is data, is being fed to the interpreter to be executed, i.e. to be interpreted as code. The fact that you have to mark s-expressions as being code or data in a specific context does not make Lisp non-homoiconic.

The point of homoiconicity is that all programs are data, not that all data are programs, so there is still a difference between the two. In Lisp, (1 2 3) is a valid list but not a valid program since an integer is not a function.

[If we look at the other great homoiconic programming language, Prolog, then we see the same phenomenon: we can build a data structure foo(X, 1, bar), but without a definition of foo, we can't execute it. Also, variables cannot be the names of predicates or facts, so X. is never a valid program.]

Lisp is self-modifying to a great degree. E.g., here's how to change the definition of a function:

[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

Explanation: at [1], we defined the function foo to be the add-1 function. At [2], we defined bar to be the add-2 function. At [3], we reset foo to the add-2 function. At [4], we see that we've successfully modified foo.

这篇关于Homoiconic和&QUOT;无限制的&QUOT;自修改code +是真的口齿不清自我修改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆