编译语言可以同音吗?

时间:2009-08-06 13:23:08

标签: compiler-construction lisp scheme interpreter homoiconicity

根据定义, homoiconic 这个词的意思是:

  

代码和数据的相同表示

在LISP中,这意味着您可以使用引用列表并对其进行评估,因此(car list)将是函数,(cdr list)是参数。这可以在编译时或在运行时发生,但它需要一个解释器。

没有编译时解释器的编译语言是否也可能同性化?或者说同性恋的概念仅限于口译员?​​

10 个答案:

答案 0 :(得分:35)

'Homoiconic'是一种含糊不清的结构。 “代码是数据”有点清楚。

无论如何,维基百科的Homoiconic上的第一句话并不是那么糟糕。它说语言必须使用其数据结构来源表示。如果我们忘记'字符串'作为源表示(这是微不足道的,并且没有那么有用的概念'homoiconic'),那么Lisp有列表,符号,数字,字符串等,用于表示源代码。 EVAL函数的接口确定语言正在处理什么类型的源表示。在这种情况下,Lisp,它不是字符串。 EVAL期望通常各种各样​​的数据结构和Lisp的评估规则确定字符串对其自身进行求值(因此不会被解释为程序表达式,而只是字符串数据)。一个数字也评估自己。列表(sin 3.0)是符号和数字的列表。评估规则指出,具有表示函数作为第一个对象的符号的该列表将被评估为函数应用程序。对于数据,特殊运算符,宏应用程序和函数应用程序,有一些这样的评估规则。就是这样。

为了说清楚:在Lisp中,函数EVAL是在Lisp数据结构上定义的。它期望数据结构,根据其评估规则对其进行评估,并返回结果 - 再次使用其数据结构。

这符合homoiconic的定义:源代码使用Lisp的数据类型具有本机表示。

现在,有趣的部分是:如何实施EVAL并不重要。重要的是它接受使用Lisp数据结构的源代码,它执行代码并返回结果。

所以 EVAL使用编译器是完全合法的。

(EVAL code)  =  (run (compile-expression code))

这就是几个Lisp系统的工作方式,有些甚至没有解释器。

所以,'Homoiconic'说SOURCE代码有一个数据表示。它并没有说在运行时必须解释源代码或执行基于此源代码。

如果编译代码,运行时既不需要编译器也不需要解释器。只有当程序想要在运行时评估或编译代码时才需要这些 - 这通常是不需要的。

Lisp还提供原始函数 READ ,它将数据的外部表示(S-Expressions)转换为数据的内部表示(Lisp数据)。因此,它还可以用于将源代码的外部表示转换为源代码的内部表示。 Lisp不对源代码使用特殊的解析器 - 因为代码是数据,只有READ。

答案 1 :(得分:8)

是肯定的。 lisp可以编译为本机二进制文件

答案 2 :(得分:3)

我觉得这是一个奇怪的问题:

首先,homoiconic部分是程序员提供的接口。语言的要点是它们抽象了一个较低级别的功能,它保留了与更高级别的表示相同的语义(虽然是一种不同的方式)。

dsm的机器代码点是一个好点,但提供:

  1. 提供的语法和语义是homoiconic
  2. 转换为较低级别的表单(机器代码或解释或其他方式)不会删除任何原始语义
  3. 为什么较低级别的实施在这里很重要?

    此外:

      

    没有编译时解释器的编译语言

    如果没有一些程序解释它,它将需要是CPU的原生,因此CPU的本地语言将需要是homoiconic(或运行代码的VM)。

    没有编译时解释的语言......会受到相当大的限制......因为它们根本不会编译

    但我不是专家,也许错过了重点。

答案 3 :(得分:2)

在最直接的形式中,C是同质的。您可以使用&functionName访问函数的表示,并使用somePtrCastToFnPtr(SomeArgs)执行数据。然而,这是在机器代码级别,如果没有某种类型的库支持,您将发现很难使用它。某种可嵌入的编译器(我似乎记得LLVM可以做到这一点)会使它更实用。

答案 4 :(得分:2)

通常编译Lisp。已经实现了JIT编译器而不是解释器。

因此,没有必要为代码是数据语言提供解释器(在“非编译器”意义上)。

答案 5 :(得分:2)

机器代码本身是同质的,所以是的。

数据或指令只是语义问题(可能是它们所在的内存的)。

答案 6 :(得分:1)

问题在于许多处理器将指令和数据区分开,并积极阻止程序修改自己的代码。这种代码过去被称为“退化代码”,并被认为是非常糟糕的事情。

解释器(和VM)没有这个问题,因为他们可以将整个程序视为数据,只有“代码”是解释器。

答案 7 :(得分:1)

是;你只需要将编译器的副本粘贴到语言运行库中。 Chez Scheme是众多优秀编译器之一。

答案 8 :(得分:1)

编译只是优化的解释。解释器接受表示代码的数据,然后“执行”该代码:代码的含义变成执行路径和数据流通过解释器的内容。编译器获取相同的数据,将其转换为另一种形式,然后将其传递给另一个解释器:一个以硅(CPU)或虚假(虚拟机)实现。

这就是为什么有些Lisp实现不能拥有解释器的原因。 EVAL函数可以编译代码然后分支到它。 EVAL和COMPILE不必具有不同的操作模式。 (Clozure,Corman Lisp,SBCL是“仅编译器”Lisps的例子。)

开头的数据部分是语言同音的关键,而不是代码的执行是否通过编译进行优化。 “代码是数据”意味着“代码是数据”而不是“可执行代码是数据”。 (当然可执行代码是数据,但是数据我们指的是我们想要操纵的代码的绝对首选表示。)

答案 9 :(得分:0)

基于VM(.net clr,jre ect)构建的语言可以使用允许快速生成代码的高级技术。其中之一是IL编织。虽然它不像ECMAScript / Lisp / Scheme等的eval那样清晰,但它可以在某种程度上模仿这种行为。

例如,检查Castle DynamicProxy以及更多交互式示例,检查LinqPAD,F#Interactive,Scala interactive。