Homoiconicity,它是如何工作的?

Aru*_*n R 38 lisp clojure

有人可以建议解释同性恋概念的文章,特别是使用Clojure.为什么Clojure是homoiconic,但在其他语言如Java中很难做到这一点?

Mic*_*zyk 24

在我继续处理一些事情之前,我想添加另一个答案,这里还有一个参考 - 与homoiconicity相关的部分相当短,但Rich Hickey正在做解释!第9频道有Rich Hickey和Brian Beckman谈论Clojure的精彩视频.可以理解的是,并发性是主要的焦点,但是同质性确实得到了它自己的(短)屏幕时间,在此期间,Rich很好地解释了它们之间的相互作用read(将程序员写下的具体语法转换为由内部表示构建的函数)列表等)和eval.他有这个漂亮的图表,显示如何eval从未知道它评估的代码来自于read在文本文件上运行...... Arthur已经解释了背后的要点,但是嘿,无论如何都要看,这是一个非常好的视频!


免责声明:我将在下一个单杠下面提到Java和Python作为示例.我想说清楚以下只是一个粗略的草图,为什么我认为制作一个同色的,Lisp风格的宏启用Java或Python可能很困难; 不过,这只是一个学术练习,我不想考虑是否有任何理由首先尝试.另外,我不想暗示具有Lisp样式宏的语言的语法必须包含树结构的显式分隔符 ; Dylan(无表情的Lisp?)显然提供了一个反例.最后,我使用表达式Lisp样式宏,因为我只检查Lisp样式宏.例如,Forth语言有一个不同的宏设施,除了我知道它可以启用邪恶酷炫的代码之外,我并不理解.显然,语法扩展可以通过多种方式实现.随着这个...


我想谈谈你的问题的第二部分 - 大多数编程语言被认为是不是同性的?我将不得不在这个过程中触及Lisp的语义,但是因为Nils已经提供了关于术语"homoiconic"本身的良好信息源的链接,并且Arthur已经描述了read - > macro expand - > compile cycle as found在Clojure中,我将在接下来的基础上进行构建.首先,让我引用Alan Kay的一篇文章(摘自Wikipedia文章,该文章也链接到原始来源):

[...]互动LISP和TRAC都是"同性恋",因为它们的内部和外部表示基本相同.

(那些[...]位隐藏了很多文本,但要点没有改变.)

现在,让我们自问一个问题:Java的Java内部表示是什么?......好吧,这甚至没有意义.Java 编译器确实具有Java 的某种内部表示,即抽象语法树; 为了构造一个"homoiconic Java",我们必须使AST表示成为Java中的第一类对象,设计一种允许我们直接编写AST的语法.这可能会相当困难.

Python提供了一个非同色语言的例子,它有趣的是它目前附带了一个ast模块形式的AST操作工具包.该模块的文档明确声明Python AST可能在发布之间发生变化,这可能会也可能不会令人沮丧; 仍然,我想一个勤奋的程序员可以采用该ast模块,设计一种语法(可能是基于S表达式,可能基于XML)直接描述Python AST并在常规Python中使用构建该语法的解析器ast,从而迈出坚实的第一步用Python语义创建一个homoiconic语言.(我相信我前段时间遇到过Lisp编译为Python字节码的方言......我想知道它是否会在某种程度上做类似的事情?)

即使这样,问题仍然是从这种同质性中提取具体的好处.它被视为Lisp语言系列成员的有益属性,因为它允许我们编写编写更多程序的程序,其中宏是最值得注意的.现在,虽然通过在Lisp中操作Lisp代码的内部表示非常容易,但是以一种方式启用宏,而Lisp执行模型也以同样重要的方式启用它们:Lisp程序只是一个集合Lisp形式; 它们由Lisp函数处理,该函数eval负责确定表达式的值并在正确的时间产生适当的副作用; Lisp的语义正是它的语义eval.内部工作如何在保持这种语义错觉的同时快速合理的问题是一个实现细节; 一个Lisp系统有义务向eval程序员公开一个函数,并且就好像该函数正在处理Lisp程序一样.

在现代Lisp系统中,它是eval合同的一部分,它执行额外的预处理阶段,在此阶段,在评估代码(或编译和运行,视情况而定)之前扩展宏.那个特殊的工具不是Lisp系统的必要部分,但它很容易插入到这个执行模型中!另外,我想知道这不是唯一使Lisp类宏转换可管理的执行模型,这意味着任何寻求合并Lisp风格宏的语言都必​​须采用类似的执行模型.我的直觉告诉我,情况确实如此.

当然,一旦用符号直接写入与AST并行的语言并使用类似Lisp的执行模型和评估器函数/对象,人们必须想知道它是否是任何机会Lisp的另一种方言......即使它的AST并行语法恰好是基于XML的.不寒而栗


Art*_*ldt 7

当我学习Lisp时,当我了解到lisp在两个阶段"编译",读取和编译以及代码用相同的数据结构表示时,同理性的想法是有意义的:

  • 首先你想到你头脑中的s表达
  • 然后在文件中键入s-expression作为字符
  • 然后读者将文件中的字符转换为s表达式.它不是编译程序,只是从字符构建数据结构,这是阅读阶段的一部分.
  • 然后读者查看每个表达式并确定它们是否是宏,如果是,则运行宏以生成另一个s表达式.所以在这一点上我们已经从s表达式转换为字符到s表达式,然后从s表达式转到不同的s表达式.
  • 然后将这些s表达式编译成.class文件,这些文件可以由jvm运行,这是"编译"阶段的第二个.

因此,从你的大脑到.class文件,它几乎都是s表达式.你甚至可以编写写s表达式的s表达式.所以你可以说"代码是数据"或"代码就是数据",因为这听起来更好.


Rai*_*wig 5

"homoiconicity"的整个想法略有混淆,并不适合Lisp.Lisp中的内部和外部表示不同.外部表示基于文件中的字符.内部表示基于Lisp数据(数字,字符串,列表,数组......),并且是非文本的.这和人物一样怎么样?有内部表示,没有相应的外部表示(例如编译代码,闭包,......).

Lisp和许多其他编程语言之间的主要区别在于,Lisp有一个简单的源代码数据表示 - 一个不基于字符串的数据表示.

显然,代码可以在基于文本的编程语言中表示为字符串.但是在Lisp中,源可以用原始Lisp数据结构来表示.外部表示基于s表达式,这是一种将分层数据表示为文本的简单模型.内部模型的表示基于列表等.

这就是评估者得到的:内部表征.不是1到1版本的文本输入,但已解析.

基本型号:

  • READ将外部s表达式转换为数据
  • EVAL以Lisp数据的形式获取Lisp表单并对其进行评估
  • PRINT将Lisp数据转换为外部s表达式

请注意,READ和PRINT适用于任意Lisp数据,它具有打印表示和读取器,而不仅适用于Lisp表单.根据定义,表单是Lisp编程语言中的有效表达式.


Kla*_*ven 5

正如 Rainer Joswig 指出的那样,我们有充分的理由怀疑同像性概念的实用性,以及 Lisp 是否真的是同像性的。

\n\n

同像性的最初定义集中在语言的内部和外部表示之间的相似性。典型的例子是 Lisp 及其 s 表达式。

\n\n

该定义和示例选择(至少)存在两个问题。

\n\n

第一个反对意见涉及外部代表。对于 Lisp,我们假设外部表示是一个 s 表达式。然而,在大多数实际的编程环境中,程序源的实际表示形式是包含字符串的文本文件。只有在解析该文本之后,该表示形式才是真正的 s 表达式。换句话说:在实际环境中,外部表示不是 s-表达式,而是文本。

\n\n

第二个反对意见涉及内部代表。出于性能原因,Lisp 解释器的实际实现通常不会在内部直接对 s 表达式进行实际操作。尽管 Lisp 可能是根据 s 表达式的案例分析来定义的,但它通常不会这样实现。因此,内部表示实际上并不是实践中的 s 表达式。

\n\n

事实上,人们甚至可能会围绕同像性的概念提出进一步的问题:对于一台封装良好的机器,我们无法通过定义观察其内部运作;从这种观点来看,使任何对机器的内部表示更一般地说,最初的定义存在这样的问题:程序只有一个外部表示和一个内部表示的想法与现实不符。事实上,存在一整套表示链,包括程序员大脑中的电子、屏幕发出的光子、程序文本、机器代码以及 CPU 中移动的电子。

\n\n

我在一篇名为的文章中更广泛地讨论了这一点我在一篇名为Don't say \xe2\x80\x9cHomoiconic\xe2\x80\x9d 的

\n