Homoiconicity,它是如何工作的?

时间:2010-02-19 12:59:26

标签: lisp clojure

有人可以推荐解释Homoiconicity概念的文章,特别是使用Clojure。为什么Clojure是homoiconic,但在Java等其他语言中很难做到这一点?

6 个答案:

答案 0 :(得分:24)

答案 1 :(得分:7)

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

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

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

答案 2 :(得分:5)

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

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

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

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

基本型号:

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

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

答案 3 :(得分:4)

这是一个做符号分化的简短程序。 这是LISP操纵自己的代码的一个例子。 尝试将其翻译成另一种语言,看看为什么LISP对这类事情有好处。

;; The simplest possible symbolic differentiator

;; Functions to create and unpack additions like (+ 1 2)
(defn make-add [ a b ] (list '+ a b))
(defn addition? [x] (and (=(count x) 3) (= (first x) '+)))
(defn add1   [x] (second x))
(defn add2   [x] (second (rest x)))

;; Similar for multiplications (* 1 2)
(defn make-mul [ a b ] (list '* a b))
(defn multiplication? [x] (and (=(count x) 3) (= (first x) '*)))
(defn mul1   [x] (second x))
(defn mul2   [x] (second (rest x)))

;; Differentiation. 
(defn deriv [exp var]
  (cond (number? exp) 0                                                              ;; d/dx c -> 0
        (symbol? exp) (if (= exp var) 1 0)                                           ;; d/dx x -> 1, d/dx y -> 0
        (addition? exp) (make-add (deriv (add1 exp) var) (deriv (add2 exp) var))     ;; d/dx a+b -> d/dx a + d/dx b
        (multiplication? exp) (make-add (make-mul (deriv (mul1 exp) var) (mul2 exp)) ;; d/dx a*b -> d/dx a * b + a * d/dx b
                                        (make-mul (mul1 exp) (deriv (mul2 exp) var)))
        :else :error))

;;an example of use: create the function x -> x^3 + 2x^2 + 1 and its derivative 
(def poly '(+ (+ (* x (* x x)) (* 2 (* x x))) 1))

(defn poly->fnform [poly] (list 'fn '[x] poly))

(def polyfn  (eval (poly->fnform poly)))
(def dpolyfn (eval (poly->fnform (deriv poly 'x))))

答案 4 :(得分:2)

正如Rainer Joswig指出的那样,有充分的理由怀疑同质性这个概念的效用,以及Lisps是否实际上是同构的。

homoiconiticy的原始定义集中在语言的内部和外部表示之间的相似性。规范的例子是Lisp,带有s表达式。

有(至少)两个有关该定义和示例选择的问题。

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

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

事实上,人们甚至可能会围绕同质性的概念提出进一步的问题:对于一个封装良好的机器,我们无法通过定义观察其内部运作;在该视图中,使关于机器内部表示的任何语句都没有意义。更一般地说,原始定义存在的问题是,程序的单个外部和单个内部表示的想法与现实不匹配。实际上,存在一整套表示,包括程序员大脑中的电子,屏幕发出的光子,程序文本,机器代码以及在CPU中移动的电子。

我在一篇名为Don't say “Homoiconic”

的文章中更广泛地写了这篇文章

答案 5 :(得分:0)

这似乎很明显,但第一个来源可能是:

http://en.wikipedia.org/wiki/Homoiconicity

http://c2.com/cgi/wiki?DefinitionOfHomoiconic

一般情况下解释了同质性,您也可以找到原始来源。正如使用Lisp的例子所解释的那样,它离Clojure不远。