同像性

在计算机编程中,同像性(homoiconicity来自希腊语单词,homo-意为相同,icon含义表像),是某些编程语言的特殊属性,这意味着用此语言书写的进程,可用使用这个语言将其作为数据来操纵,因此只要阅读进程自身,就能推论出来这个进程的内部表示。该属性经常被归结成,这个语言将“代码当作”。

简介

在同像性编程语言中,进程的主要表示方式,也是属于这个语言自身的原始类型的一种数据结构。这使得在这种语言中的元编程,比在没有这个属性的语言中要更加容易:在这种语言中的反射(在运行时检查进程的实体),取决於单一的、同质的结构,而且它不必去处理以复杂语法形式出现的其它一些结构。同像性语言典型的包括对语法宏的完全支持,这允许编程者以简明方式来表达进程变换。

Lisp编程语言,是具有同像属性的典型范例,它设计得易于进行列表操纵,而且其结构用具有嵌套列表形式的S-表达式来给出,它可以由其他LISP代码来操纵[1]。这类语言的其他例子有Clojure(一种现代流行的LISP方言),RebolRefal,以及最近的Julia等编程语言。

历史

同像性一词的原始来源,是论文《编译器语言的宏指令扩展》[2]。其依据是早期具影响力的论文《TRAC文本处理语言》[3]

TRAC的主要设计目标之一,是其输入脚本(用户所输入),应该同一于指示TRAC处理器内部动作的文本。换句话说,TRAC过程应该是以字符串形式保存于内存中,正如同用户在键盘上键入的那样。如果TRAC过程本身演化出新的过程,这些新过程也应该在同一个脚本中陈述出来。TRAC处理器在其动作中,将此脚本解释为它的进程。换句话说,TRAC翻译器进程(处理器),将这个计算机有成效地转换为,具有新进程语言即TRAC语言的新计算机。在任何时候,进程或过程信息都应当能够,以同于TRAC处理器在运行期间作用于其上的形式来显示出来。我们期望内部的字符代码表示,同一于或非常相似于,外部的代码表示。在当前的TRAC实作中,内部字符表示基于ASCII,因为TRAC过程和文本,在处理器内部和外部,都具有相同的表示,所以术语同像性(homoiconic)一词是适用的,homo涵义相同,icon义为表像。

[...]

跟从沃伦·麦卡洛克的提议,依据查尔斯·桑德斯·皮尔士的术语,参见道格拉斯·麦克罗伊的“编译器语言的宏指令扩展”,ACM通信,页214-220; 1960年4月。

艾伦·凯在他1969年的博士论文中,使用并可能由此推广了同像性这个术语[4]

所有先前的系统中,显著的一组例外是Interactive LISP[...]和TRAC。两者都是面向功能性的(一为列表,另一为字符串),都用一种语言与用户交谈,并且都具有 “同像性”,因为它们内部和外部表示本质上相同。它们都具有动态创建新函数的能力,然后可随着用户的喜好而精工细作。它们唯一最大的缺点是,以它们写出的进程看起来就像,苏美尔人把布尔那·布里亚什国王的信写成巴比伦楔形文![...]

用途及优点

同像性的一个优点是,向这个语言扩展新概念变得更加简单,因为表示代码的数据,可在进程的层和基础层之间传递。函数的抽象语法树,可以作为元层中的数据结构来合成和操纵,然后再被求值。它可以更容易理解如何操纵代码,因为它可以被理解为简单的数据(因为语言本身的格式同于数据格式)。

同像性的典型演示是元循环求值器

实作方法

所有范纽曼型架构的系统,其中包括绝大多数当今的通用计算机,由于原始机器代码在内存中的运行方式,其数据类型是字节,故而可以隐含地描述为具有同像性。但是这个特征也可以在编程语言层别上抽象出来。

Lisp及其方言例如SchemeClojureRacket等,使用S-表达式来实现同像性。

其他被认为具有同像性的语言包括:

同像性语言的编程范例

Lisp

Lisp使用S-表达式作为数据和源码的外部表示。S-表达式可以用原始Lisp函数READ读取。READ返回Lisp数据:列表、符号、数字和字符串。原始Lisp函数EVAL使用以数据形式表示的Lisp代码,计算副作用并得出返回结果。结果由原始Lisp函数PRINT打印出来,它从Lisp数据产生一个外部的S-表达式。下面示例采用Common LispSBCL实现。

以下Lisp示例,构造出的列表含有结构类型person:它有两个属性nameage,其类型分别是字符串和整数:

* (defstruct person name age)
PERSON

* (person-name (cadr (list (make-person :name "john" :age 20) (make-person :name "mary" :age 18) (make-person :name "alice" :age 22))))
"mary"

以下Lisp代码示例,使用了列表、符号和数值:

* (* (sin 1.1) (cos 2.03))      ; 中缀表示法为 sin(1.1)*cos(2.03)
-0.39501375

使用原始Lisp函数LIST产生上面的表达式,并将变量EXPRESSION设置为结果:

* (defvar expression)
EXPRESSION

* (setf expression  (list '* (list 'sin 1.1) (list 'cos 2.03)) )  
(* (SIN 1.1) (COS 2.03))
; Lisp传回并打印结果

* (third expression)    ; 表达式中的第三项
(COS 2.03)

COS这项变更为SIN

* (setf (first (third expression)) 'SIN)
SIN
; 变更之后的表达式为 (* (SIN 1.1) (SIN 2.03)).

求值表达式:

* (eval expression)
0.79888344

将表达式打印到字符串:

* (princ-to-string expression)
"(* (SIN 1.1) (SIN 2.03))"

从字符串中读取表达式:

* (read-from-string "(* (SIN 1.1) (SIN 2.03))")
(* (SIN 1.1) (SIN 2.03))
24
; 传回一个其中有列表,数字和符号的列表

Prolog

Prolog是同像性语言并且提供了很多反射设施。

1 ?- X is 2*5.
X = 10.

2 ?- L = (X is 2*5), write_canonical(L).
is(_, *(2, 5))
L = (X is 2*5).

3 ?- L = (ten(X):-(X is 2*5)), write_canonical(L).
:-(ten(A), is(A, *(2, 5)))
L = (ten(X):-X is 2*5).

4 ?- L = (ten(X):-(X is 2*5)), assert(L).
L = (ten(X):-X is 2*5).

5 ?- ten(X).
X = 10.

6 ?-

在第4行创建一个新子句。算符:-分隔一个子句的头部和主体。通过assert/1将它增加到现存的子句中,即增加它到“数据库”,这样我们可以以后调用它。在其他语言中可以称为“在运行时间创建一个函数”。还可以使用abolish/1retract/1从数据库中移除子句。注意在子句名字后的数,是它可以接受的实际参数的数目,它也叫做元数

我们可以查询数据库来得到一个子句的主体:

7 ?- clause(ten(X),Y).
Y = (X is 2*5).

8 ?- clause(ten(X),Y), Y = (X is Z).
Y = (X is 2*5),
Z = 2*5.

9 ?- clause(ten(X),Y), call(Y).
X = 10,
Y = (10 is 2*5).

call类似于Lisp的eval函数。

Rebol

Rebol可巧妙的演示将代码当作数据来操纵和求值的概念。Rebol不像Lisp,不要求用圆括号来分隔表达式。下面是Rebol代码的例子,注意>>表示解释器提示符,出于可读性而在某些元素之间增加了空格:

>> repeat i 3 [ print [ i "hello" ] ]
1 hello
2 hello
3 hello

在Rebol中repeat事实上是内建函数而非语言构造或关键字。通过将代码包围在方括号中,解释器不求值它,而是将它当作包含字的块:

[ repeat i 3 [ print [ i "hello" ] ] ]

这个块有类型block!,并且使用近乎赋值的语法,可以进一步的将它指定为一个字的值,这种语法实际上可以被解释器理解为特殊类型set-word!,并采用一个字跟随一个冒号的形式:

>> block1: [ repeat i 3 [ print [ i "hello" ] ] ] ;; 将这个块的值赋值给字`block1`
== [repeat i 3 [print [i "hello"]]]
>> type? block1 ;; 求值字`block1`的类型
== block!

这个块仍可以使用Rebol中提供的do函数来解释,它类似于Lisp中的eval。有可能审查块的元素并变更它们的值,从而改变要求值代码的行为:

>> block1/3 ;; 这个块的第三个元素
== 3
>> block1/3: 5 ;; 设置第三个元素的值为5
== 5
>> probe block1 ;; 展示变更了的块
== [repeat i 5 [print [i "hello"]]]
>> do block1 ;; 求值这个块
1 hello
2 hello
3 hello
4 hello
5 hello

另见

参考文献

引用
  1. Wheeler, David A. . [2022-01-29]. (原始内容存档于2022-01-29).
  2. McIlroy, Douglas. . Comm. ACM. 1960, 3 (4): 214–220. doi:10.1145/367177.367223.
  3. Mooers, C.N.; Deutsch, L.P. . . 1965: 229–246. doi:10.1145/800197.806048.
  4. Kay, Alan. (学位论文). University of Utah. 1969 [2014-03-28]. (原始内容存档于2018-09-15).
  5. . [2020-04-23]. (原始内容存档于2013-04-23).
  6. . 8thlight.com. [2022-01-29]. (原始内容存档于2022-03-05). Elixir, on the surface, is not homoiconic. However, the syntax on the surface is just a facade for the homoiconic structure underneath.
  7. . julialang.org. [2020-04-23]. (原始内容存档于2019-02-19). We want a language that’s homoiconic, with true macros like Lisp, but with obvious, familiar mathematical notation like Matlab.
  8. . docs.julialang.org. [2020-04-23]. (原始内容存档于2013-05-04). Like Lisp, Julia represents its own code as a data structure of the language itself.
  9. Shapiro, Ehud Y.; Sterling, Leon. . MIT Press. 1994. ISBN 0-262-19338-8.
  10. (PDF): 6, 2021-05-18 [2022-01-29], (原始内容 (PDF)存档于2022-04-22), ... the semantics are of the FPL (functional programming language) variety with stronger affinities with Lisp and APL. In particular, it allows “computing on the language”, which in turn makes it possible to write functions that take expressions as input, something that is often useful for statistical modeling and graphics.
  11. , [2022-01-29], (原始内容存档于2022-01-29)
  12. Homoiconic languages (archived), in true Blue blog at Oracle
  13. Ramsay, S.; Pytlik-Zillig, B. . . 2012 [2020-04-23]. (原始内容存档于2016-03-03).
  14. . Stack Exchange. [2020-04-23]. (原始内容存档于2018-08-20). Mathematica is [...] Homoiconic language (programs written in own data structures - Mathematica expressions. This is code-as-data paradigm, like Lisp which uses lists for this)
  15. . Wolfram Language. Wolfram. 2017 [2020-04-23]. (原始内容存档于2022-01-04).

外部链接

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.