问题标签 [homoiconicity]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
4 回答
6300 浏览

assembly - Homoiconic 和“不受限制”的自我修改代码 + lisp 真的是自我修改吗?

我承认我对 Lisp 的了解非常少。但是我对这门语言非常感兴趣,并计划在不久的将来开始认真学习它。我对这些问题的理解无疑是有缺陷的,所以如果我说了什么明显错误的话,请评论和纠正我,而不是投反对票。

真正的同音和自修改语言

我正在寻找支持 Homoiconicity(代码与数据具有相同的表示形式)和无限制的自我修改(无限制意味着您可以更改正在运行的代码的各个方面,而不仅仅是发出新代码或更改函数指针/代表。)

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

  1. 机器码。Homoiconic 因为一切都是数字。可不受限制地修改,因为它包含指针,可用于操作任何内存地址,无论该地址是否包含代码或数据。
  2. 马尔堡。与机器代码相同的推理。每条指令在执行后都会自我修改
  3. 脱氧核糖核酸。不是编程语言,但仍然很有趣。它不像机器代码那样自我修改;实际指令+数据被修改到位的地方。然而,它是自我复制的,可以根据之前的状态变异/进化(辐射等副作用时不时地把它搞砸)。无论如何,这只是一种间接的自我修改方式。简而言之,DNA可以自我修改,但它是通过在其整体中复制自身以及相关突变来实现的。DNA 的物理串是“不可变的”。

为什么 Lisp 不在此列表中

Lisp 不在该列表中,因为在我看来 Lisp几乎是同音异形的,并且只支持受限的自我修改。你可以做类似的事情

这将做同样的事情

在第一个版本中(+ 1 2 3)是原始代码,而在第二个版本中是数据。通过假设这个陈述的真实性,可以说 Lisp 甚至不是 homiconic。代码具有与数据相同的表示形式,因为它们都是列表/树/S 表达式。但是,您必须明确标记这些列表/树/S 表达式中的哪些是代码,哪些是对我来说是数据,这一事实似乎表明 Lisp 毕竟不是 homiconic。这些表示非常相似,但它们在微小的细节上有所不同,您必须实际说明您是在处理代码还是数据。这绝不是一件坏事(事实上其他任何事情都是疯狂的),但它突出了 Lisp 和机器代码之间的区别。在机器代码中,您不必明确标记哪些数字是指令,哪些是指针,哪些是数据。

这是反对不受限制的自我修改的更有力的案例。当然,您可以获取代表一些代码的列表并对其进行操作。例如改变

然后你运行它eval。但是当你这样做时,你只是在编译一些代码并运行它。您不是在修改现有代码,您只是在发布和运行新代码。C# 可以使用表达式树做同样的事情,即使格式不太方便(这是由于 C# 代码对其 AST 具有不同的表示形式,而不是 Lisp,它它自己的 AST)。您是否真的可以获取整个源文件并在整个源文件运行时开始修改它,对源文件所做的更改会对程序行为产生实时影响?

除非有某种方法可以做到这一点,否则 Lisp 既不是 homiconic 也不是自我修改的。(为了推迟对定义的争论,Lisp 不像机器代码那样同音或自我修改。

使 Lisp Homoiconic/无限制地自我修改的方法

我可以看到 3 种潜在的方法来使 Lisp 像机器代码一样具有同义性/可自我修改。

  1. 非冯诺依曼架构。如果有人可以发明一些惊人的假设机器,其中程序的最低级别表示是可以直接执行的 AST(无需进一步编译)。在这样的机器上,AST 既代表可执行指令,也代表数据。不幸的是,问题还没有解决,因为 AST 仍然必须是代码或数据。eval 函数的出现不会改变这一点。在机器代码中,您可以根据需要在代码和数据之间来回切换。而使用 eval 和 Lisp 后,一旦您将某个列表从数据“评估”到代码并执行了它,就无法再次将该列表作为数据取回。实际上,该列表已永远消失,并已被其价值所取代。我们会遗漏一些关键的东西,这恰好是指针。
  2. 列出标签。如果要求每个列表也具有唯一标签,则可以通过对具有给定标签的列表运行函数来进行间接自我修改。结合延续,这最终将允许在与机器代码相同的意义上自我修改代码。标签等同于机器代码内存地址。例如,考虑一个 Lisp 程序,其中 AST 的顶部节点具有标签“main”。然后,在 main 中,您可以执行一个函数,该函数接受一个标签、一个整数、一个原子,并将原子复制到列表中,其标签与提供给函数的标签相匹配,位于整数指定的索引处。然后只需在 main 上调用当前的继续。你去,自我修改代码。
  3. Lisp 宏。我没有花时间去理解 Lisp 宏,它们实际上可能完全符合我的想法。

第 1 点与第 2 点相结合将产生一个完全自我修改的 Lisp。前提是可以生产所描述的神奇的 Lisp 机器。2. 单独可以产生一个自我修改的 Lisp,但是在冯诺依曼架构上的实现可能非常低效。

问题

  1. 除了机器码、dna 和 malbolge 之外,还有什么语言可以进行完全的自我修改并且是同音的?
  2. (如果您在上面的文字中做了一个 tl;dr,请不要费心回答)。lisp 真的是谐音+自我修改吗?如果你这么说,你能准确引用我的论点中我误入歧途的地方吗?

附录

具有不受限制的自我修改但没有同音性的语言

  1. 集会。该代码使用单词而不是数字,因此失去了同义性,但它仍然具有指针,它保留了对内存的完全控制并允许不受限制的自我修改。
  2. 任何使用原始指针的语言。例如 C/C++/Objective C。与 Assembly 相同的参数
  3. 包含虚拟指针的 JIT 语言。例如在不安全的上下文中运行的 C#/.net。与大会相同的论点。

其他可能相关/有趣的概念和语言:Lisp、Ruby、Snobol、Forth 和它的编译时元编程、Smalltalk 和它的反射、无类型的 lambda 演算及其属性,即一切都是函数(这意味着假设我们可以发明一台直接执行 lambda 演算的机器,lambda 演算将是同形的,而 Von Neumann 机器代码在该机器上运行时不会。[并且 Godels theorem 将是可执行的。哈哈,可怕的想法:P])

0 投票
4 回答
527 浏览

clojure - 是否可以分解 Clojure 函数?

虽然我可能错误地解释了同音性的概念,但我将其理解为“代码即数据”。

所以,我可以这样写代码:

此时,helo只是数据,但可以像这样执行代码:

返回“Hello world”。

我还可以继续helo当作数据来对待:

分别返回str3

到目前为止,一切都很好。但是,一旦我将代码包装在一个函数中,我似乎就失去了将代码视为数据的能力:

我该如何分解helofn?看来我不能把它当作数据;如果我这样做:

我得到一个例外:

java.lang.UnsupportedOperationException:此类型不支持计数:user$helofn

是否有另一种分解方法helofn,或者我只是对同音性期望过高?

0 投票
1 回答
495 浏览

lisp - 同调性水平

这是对我之前的问题的跟进。我不相信 Lisp 代码与 Von Neumann 架构上的机器代码一样具有同义性。在我看来,在这两种情况下,代码都表示为数据,但很明显,您可以在机器代码中比在 Lisp 中更自由地利用此属性。

当乱搞机器代码时,自我修改代码非常容易,它总是会发生,通常是偶然的,并且(根据我的经验)会产生有趣的结果。在编写一个简单的“打印数字 0-15”程序时,我的一个指针可能会出现“减一”错误。我最终会不小心将寄存器 1 中的任何内容转储到包含下一条指令的内存地址中,而是执行随机指令。(当它是某种“goto”时总是很棒。上帝知道它会在哪里结束,以及在那之后它会做什么)

代码和数据之间确实没有分离。一切都同时是一条指令(即使它只是一个 NOP)、一个指针和一个普通的旧数字。代码可能会在您眼前发生变化。

请帮助我解决我一直在摸索的 Lisp 场景。假设我有以下程序:

现在我想要在这个程序中添加一些 Lisp 代码,这些代码会将 * 更改为 +,将 <= 更改为 >=,将 (+ 1 2 3) 粘贴到某处,并且通常会破坏函数向上。然后我希望程序执行导致的绝对混乱。

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

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

0 投票
2 回答
117 浏览

reflection - 如何打印一个块而不在 Rebol 中对其进行评估

我正在尝试将代码生成器放在一起,并且需要打印一个块(包含一些目标语言的代码)而不对其(即块)进行评估。我该怎么做呢?

编辑 1——我知道如果我将 Ruby 代码嵌入为字符串,这可以很容易地完成,但由于 Rebol 解析器似乎并不介意,我想为什么不呢?

0 投票
1 回答
297 浏览

emacs - 为什么将代码视为 lisp 中的数据很有用

我现在学习 emacs lisp,我想知道为什么将代码视为数据可能有用。这种方法有什么好处。我看到了一种解释,因为这是传统冯诺依曼架构的替代方案,传统的冯诺依曼架构在数据和代码之间存在明确的分离。我想了解这个决定的含义,明白这个想法。

在此先感谢,尼克。

0 投票
1 回答
6633 浏览

lisp - Elixir 和 Julia 之类的语言在什么意义上是谐音的?

Lisp 中的同音性很容易看出:

(+ 1 2)

既是函数调用+with 1,2作为参数,也是一个包含+,1和的列表2。它同时是代码和数据。

但是,在像 Julia 这样的语言中:

1 + 2

我知道我们可以Expr在 Julia 中将其解析为:

:(1 + 2)

然后我们可以获取 AST 并对其进行操作:

julia> Meta.show_sexpr(:(1+2)) (:call, :+, 1, 2)

因此,我们可以在 Julia(和 Elixir)中操作程序的 AST。但是它们是否与 Lisp 具有相同的意义?任何代码片段真的只是语言本身的数据结构吗?

我看不出1 + 2Julia 中的代码是如何立即成为数据的——就像(+ 1 2)Lisp 中的那样只是一个列表。那还是谐音吗?

0 投票
1 回答
204 浏览

reflection - 哪些情况难以区分代码和数据?

据说代码是 Rebol 和 Red 中的数据(反之亦然,即同音符号)。此外,据说无法区分两者。我的理解是这里有两种情况:

  1. 从代码和数据的混合 确定代码
  2. 从代码和数据的混合 确定数据

代码和数据的混合是我的名字,外人通常称之为 Rebol 代码,而有经验的 Rebol 程序员则说是数据(没有代码,只有数据)

动机

代码与数据的区别使编程语言中的某些功能更容易。例如,提到了反汇编(sbcl 具有该disassemble功能)。

问题

这些有问题的案例有哪些例子?

语境:

来自 2017 年 3 月 15 日下午 3:32 的聊天:(强调我的)

Didec:你忘记了 Redbol 中没有代码,只有数据。

Maximvl:嗯,CL 和 SBCL 都是一样的

在 Lisp 语言中不一样,“代码”和“数据”[在 Lisp 中] 之间存在区别,因为代码必须以call开头。Redbol 对代码没有这样的限制,这使得它非常不同。

还:

此外,上下文和动态绑定使其更加灵活,但同时,像在您的 CL 示例中那样直接转换为低级汇编代码是不可能的

旁白:这是否意味着 Rebol 比 Lisp 更具有谐音性?

0 投票
1 回答
112 浏览

clojure - 如何使 clojure 程序结构更容易识别?

Clojure 作为一种 Lisp 方言,继承了 Lisp 的同音性。同质性使元编程更容易,因为代码可以被视为数据:语言中的反射(在运行时检查程序的实体)依赖于单一的同质结构,并且它不必处理以复杂语法出现的几种不同结构[1]

更同质的语言结构的缺点是语言结构,如循环、嵌套 if、函数调用或开关等,彼此更相似。

在 Clojure 中:

两种构造之间的区别只是一个词。在非同音语言中:

有没有办法让这些程序结构在 Clojure 中更容易识别(更显眼)?也许一些推荐的代码格式或最佳实践?

0 投票
2 回答
241 浏览

haskell - 存在构造函数的模式绑定

作为一个接触过 Lisp 的程序员,在编写 Haskell 时,我注意到了一些奇怪的东西,我没能理解。

这编译得很好:

而这失败了:

对我来说,第二个片段失败的原因并不明显。

问题是:

我是否错过了某些东西或由于 haskell 不是同音异形这一事实而导致了这种行为?

我的理由是,鉴于:

  1. Haskell 需要将记录模式匹配实现为编译器扩展,因为它选择使用语法而不是数据。

  2. 函数头或 let 子句中的匹配是两种特殊情况。

很难理解这些特殊情况,因为它们既不能实现,也不能直接在语言本身中查找。

因此,无法保证整个语言的一致行为。尤其是与其他编译器扩展一起,例如。

ps:编译错误:

编辑:不同的编译器版本会针对相同的问题给出此错误

0 投票
4 回答
343 浏览

clojure - Clojure 比其他 lisps 的同音性更低吗?

我记得在Clojure for Lisp Programmers 视频中重复过的一个说法是,早期 Lisp,尤其是 Common Lisp 的一个很大的弱点是,太多地与 Lisps 的列表结构,尤其是cons单元格结合在一起。您可以在链接视频的第 25 分钟处找到一次这种说法,但我确信我记得在该系列的其他地方听到过这种说法。重要的是,在视频的同一点,我们看到了这张幻灯片,它向我们展示了 Clojure 有许多其他的数据结构,而不仅仅是老式的 Lispy 列表: 在此处输入图像描述 这让我很困扰。我对 Lisp 的了解非常有限,但我一直被告知,其传奇的元可编程性的一个关键要素是,一切——是的,一切——都是一个列表,而且这就是防止我们在尝试对其他语言进行元编程时遇到的那种错误的原因。这是否表明通过添加新的一流数据结构,Clojure 降低了其同音性,从而使其比其他 Lisp(例如 Common Lisp)更难进行元编程?