fbpx
维基百科

同像性

在计算机编程中,同像性(homoiconicity來自希臘語單詞,homo-意為相同,icon含義表像),是某些编程语言的特殊屬性,它意味着一个程序的结构与其句法是相似的,因此易于通过阅读程序来推测程序的内在涵义。如果一门编程语言具备了同像性,说明该语言的文本表示(通常指源代码),與其抽象語法樹(AST)具有相同的結構(即AST和語法是同形的)。该特性允許使用相同的表示語法,將語言中的所有代碼當成数据,來存取以及轉換,提供了“代码即数据”的理论前提。

簡介

同像性編程語言中,程序的主要呈現方式,也是語言本身原始類型中的資料結構。這使得元編程更加容易,因為程序代碼可以被視為資料:語言中的反射(運行時檢查程序的實體)取決於單一的、性質相同的結構,而且它不必去處理,其它一些不同結構所導致的複雜語法。換句話說,同像性是程序的源代碼即是基本的資料結構,而這個語言本身知道如何存取源碼的文本。

Lisp編程语言,是具有同像性質的典型範例,它的設計很容易進行對列表的操作,而且其語法結構,即採用嵌套列表形式的S-表达式[1]。LISP程式以列表的形式來編寫,所以可在運行時存取本身擁有的函數和程序,並以編程的方式重新設計自己。具有同像屬性的語言,通常有對句法巨集的全面支持,允許程序員以簡明的方式來表達程序的變換。這類語言有Clojure(現代流行的LISP方言),RebolRefal英语Refal,以及最近的Julia等等編程語言。

歷史

同像性一詞的原始來源,是論文《編譯器語言的巨集指令擴展》[2]。根據早期具影響力的論文《TRAC英语TRAC (programming language)文本處理語言》中提到[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的列表導向的語言的情況下,它會消除許多能幫助人們分析語言結構的視覺線索,而可能導致陡峭的學習曲線[5]

同像性的典型演示是元循環求值(meta-circular evaluator,同於REPL)。

實作方法

所有范紐曼型架構的系統,其中包括絕大多數當今的通用計算機,由於原始機器代碼在記憶體中執行的資料類型是位元組,可以隱含地描述為具有同像性。但是這個功能也可以在編程語言層別就抽取出來。

Lisp及其方言例如SchemeClojureRacket等,使用S-表達式來實現同像性。

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

同像性語言的編程範例

Lisp

Lisp使用S-表達式作為資料和源碼的外部表示。可以用基本函數READ讀取S-表達式。READ回傳Lisp資料:列表、符號、數字和字串。基本函數EVAL使用以資料形式呈現的Lisp源碼,計算副作用並得出返回結果。結果由基本函數PRINT打印出來,從Lisp資料產生一個外部的S-表達式。

Lisp資料是含有不同類型的列表:(子)列表,符號,字串和整數。

((:name "john" :age 20) (:name "mary" :age 18) (:name "alice" :age 22)) 

以下Common Lisp源碼範例使用列表,符號和數字。

(* (sin 1.1) (cos 2.03)) ; 中綴表示法為 sin(1.1)*cos(2.03) 

使用基本函數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 1.1) (SIN 2.03)). 

評估表達式:

(eval expression) -> 0.7988834 

將表達式打印到字串:

(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)) ; 傳回一個其中有列表,數字和符號的列表 

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. Macro Instruction Extensions of Compiler Languages. Comm. ACM. 1960, 3 (4): 214–220. doi:10.1145/367177.367223. 
  3. ^ Mooers, C.N.; Deutsch, L.P. TRAC, A Text-Handling Language. Proceeding ACM '65 Proceedings of the 1965 20th national conference. 1965: 229–246. doi:10.1145/800197.806048. 
  4. ^ Kay, Alan. (学位论文). University of Utah. 1969 [2014-03-28]. (原始内容存档于2018-09-15). 
  5. ^ . [2022-01-29]. (原始内容存档于2022-05-16). 
  6. ^ 6.0 6.1 6.2 6.3 6.4 6.5 6.6 6.7 Homoiconic Languages. [2020-04-23]. (原始内容于2013-04-23). 
  7. ^ . 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. 
  8. ^ Why we created Julia. 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. 
  9. ^ metaprogramming. docs.julialang.org. [2020-04-23]. (原始内容于2013-05-04). Like Lisp, Julia represents its own code as a data structure of the language itself. 
  10. ^ Shapiro, Ehud Y.; Sterling, Leon. The art of Prolog: advanced programming techniques. MIT Press. 1994. ISBN 0-262-19338-8. 
  11. ^ (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. 
  12. ^ , [2022-01-29], (原始内容存档于2022-01-29) 
  13. ^ , in true Blue blog at Oracle
  14. ^ Ramsay, S.; Pytlik-Zillig, B. Code-Generation Techniques for XML Collections Interoperability. dh2012 Digital Humanities Conference Proceedings. 2012 [2020-04-23]. (原始内容于2016-03-03). 
  15. ^ Metaprogramming in mathematica. 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) 
  16. ^ . Wolfram Language. Wolfram. 2017 [2020-04-23]. (原始内容存档于2022-01-04). 

外部連結

  • Definition of Homoiconic at the C2 Wiki (页面存档备份,存于互联网档案馆

同像性, 在计算机编程中, homoiconicity來自希臘語單詞, homo, 意為相同, icon含義表像, 是某些编程语言的特殊屬性, 它意味着一个程序的结构与其句法是相似的, 因此易于通过阅读程序来推测程序的内在涵义, 如果一门编程语言具备了, 说明该语言的文本表示, 通常指源代码, 與其抽象語法樹, 具有相同的結構, 即ast和語法是同形的, 该特性允許使用相同的表示語法, 將語言中的所有代碼當成数据, 來存取以及轉換, 提供了, 代码即数据, 的理论前提, 目录, 簡介, 歷史, 用途及優缺點, 實作. 在计算机编程中 同像性 homoiconicity來自希臘語單詞 homo 意為相同 icon含義表像 是某些编程语言的特殊屬性 它意味着一个程序的结构与其句法是相似的 因此易于通过阅读程序来推测程序的内在涵义 如果一门编程语言具备了同像性 说明该语言的文本表示 通常指源代码 與其抽象語法樹 AST 具有相同的結構 即AST和語法是同形的 该特性允許使用相同的表示語法 將語言中的所有代碼當成数据 來存取以及轉換 提供了 代码即数据 的理论前提 目录 1 簡介 2 歷史 3 用途及優缺點 4 實作方法 5 同像性語言的編程範例 5 1 Lisp 5 2 Prolog 5 3 Rebol 6 另見 7 参考文献 8 外部連結簡介 编辑同像性編程語言中 程序的主要呈現方式 也是語言本身原始類型中的資料結構 這使得元編程更加容易 因為程序代碼可以被視為資料 語言中的反射 運行時檢查程序的實體 取決於單一的 性質相同的結構 而且它不必去處理 其它一些不同結構所導致的複雜語法 換句話說 同像性是程序的源代碼即是基本的資料結構 而這個語言本身知道如何存取源碼的文本 Lisp編程语言 是具有同像性質的典型範例 它的設計很容易進行對列表的操作 而且其語法結構 即採用嵌套列表形式的S 表达式 1 LISP程式以列表的形式來編寫 所以可在運行時存取本身擁有的函數和程序 並以編程的方式重新設計自己 具有同像屬性的語言 通常有對句法巨集的全面支持 允許程序員以簡明的方式來表達程序的變換 這類語言有Clojure 現代流行的LISP方言 Rebol和Refal 英语 Refal 以及最近的Julia等等編程語言 歷史 编辑同像性一詞的原始來源 是論文 編譯器語言的巨集指令擴展 2 根據早期具影響力的論文 TRAC 英语 TRAC programming language 文本處理語言 中提到 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的列表導向的語言的情況下 它會消除許多能幫助人們分析語言結構的視覺線索 而可能導致陡峭的學習曲線 5 同像性的典型演示是元循環求值 meta circular evaluator 同於REPL 實作方法 编辑所有范紐曼型架構的系統 其中包括絕大多數當今的通用計算機 由於原始機器代碼在記憶體中執行的資料類型是位元組 可以隱含地描述為具有同像性 但是這個功能也可以在編程語言層別就抽取出來 Lisp及其方言例如Scheme Clojure Racket等 使用S 表達式來實現同像性 其他被认为具有同像性的语言包括 Curl 6 Elixir 7 Io 6 Julia 8 9 6 Prolog 6 10 R语言 11 12 Rebol 6 Red 英语 Red programming language SNOBOL 6 Tcl 13 6 XSLT 14 Refal 英语 Refal 6 Rexx Wolfram语言 15 16 同像性語言的編程範例 编辑Lisp 编辑 Lisp使用S 表達式作為資料和源碼的外部表示 可以用基本函數READ讀取S 表達式 READ回傳Lisp資料 列表 符號 數字和字串 基本函數EVAL使用以資料形式呈現的Lisp源碼 計算副作用並得出返回結果 結果由基本函數PRINT打印出來 從Lisp資料產生一個外部的S 表達式 Lisp資料是含有不同類型的列表 子 列表 符號 字串和整數 name john age 20 name mary age 18 name alice age 22 以下Common Lisp源碼範例使用列表 符號和數字 sin 1 1 cos 2 03 中綴表示法為 sin 1 1 cos 2 03 使用基本函數LIST產生上面的表達式 並將變量EXPRESSION設置為結果 defvar expression gt EXPRESSION setf expression list list sin 1 1 list cos 2 03 gt SIN 1 1 COS 2 03 Lisp傳回並打印結果 third expression 表達式中的第三項 gt COS 2 03 將COS這項變更為SIN setf first third expression SIN 變更之後的表達式為 SIN 1 1 SIN 2 03 評估表達式 eval expression gt 0 7988834 將表達式打印到字串 princ to string expression gt SIN 1 1 SIN 2 03 從字串中讀取表達式 read from string SIN 1 1 SIN 2 03 gt SIN 1 1 SIN 2 03 傳回一個其中有列表 數字和符號的列表 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 1或retract 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代码的例子 注意 gt gt 表示解释器提示符 出于可读性而在某些元素之间增加了空格 gt gt span class nv repeat span span class nf i span span class nf 3 span span class nv print span span class nv i span span class c hello span 1 hello 2 hello 3 hello 在Rebol中repeat事实上是内建函数而非语言构造或关键字 通过将代码包围在方括号中 解释器不求值它 而是将它当作包含字的块 repeat i 3 print i hello 这个块有类型block 并且使用近乎赋值的语法 可以进一步的将它指定为一个字的值 这种语法实际上可以被解释器理解为特殊类型set word 并采用一个字跟随一个冒号的形式 gt gt span class err block span span class m 1 span span class err span span class nv repeat span span class nf i span span class nf 3 span span class nv print span span class nv i span span class c hello span 将这个块的值赋值给字 block1 repeat i 3 print i hello gt gt span class nv type span span class nf span span class nv block1 span 求值字 block1 的类型 block 这个块仍可以使用Rebol中提供的do函数来解释 它类似于Lisp中的eval 有可能审查块的元素并变更它们的值 从而改变要求值代码的行为 gt gt span class nv block1 span span class nf span span class m 3 span 这个块的第三个元素 3 gt gt span class nv block1 span span class nf span span class m 3 span span class err span span class nf 5 span 设置第三个元素的值为5 5 gt gt span class nv probe span span class nf block1 span 展示变更了的块 repeat i 5 print i hello gt gt span class nv do span span class nf block1 span 求值这个块 1 hello 2 hello 3 hello 4 hello 5 hello另見 编辑标记法的认知维度 英语 Cognitive dimensions of notations 编程语言语法的设计原理 串接编程语言 面向语言编程 符号式编程 自修改代码 LISP 同像性语言的可能最周知的例子 元编程 对同像性非常有用的编程技术 实化 参考文献 编辑引用 Wheeler David A Readable Lisp S expressions 2022 01 29 原始内容存档于2022 01 29 McIlroy Douglas Macro Instruction Extensions of Compiler Languages Comm ACM 1960 3 4 214 220 doi 10 1145 367177 367223 Mooers C N Deutsch L P TRAC A Text Handling Language Proceeding ACM 65 Proceedings of the 1965 20th national conference 1965 229 246 doi 10 1145 800197 806048 Kay Alan The Reactive Engine 学位论文 University of Utah 1969 2014 03 28 原始内容存档于2018 09 15 The Lisp Curse 2022 01 29 原始内容存档于2022 05 16 6 0 6 1 6 2 6 3 6 4 6 5 6 6 6 7 Homoiconic Languages 2020 04 23 原始内容存档于2013 04 23 Lispy Elixir 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 Why we created Julia 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 metaprogramming docs julialang org 2020 04 23 原始内容存档于2013 05 04 Like Lisp Julia represents its own code as a data structure of the language itself Shapiro Ehud Y Sterling Leon The art of Prolog advanced programming techniques MIT Press 1994 ISBN 0 262 19338 8 R Language Definition 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 expression Unevaluated Expressions 2022 01 29 原始内容存档于2022 01 29 Homoiconic languages archived in true Blue blog at Oracle Ramsay S Pytlik Zillig B Code Generation Techniques for XML Collections Interoperability dh2012 Digital Humanities Conference Proceedings 2012 2020 04 23 原始内容存档于2016 03 03 Metaprogramming in mathematica 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 Notes for Programming Language Experts Wolfram Language Wolfram 2017 2020 04 23 原始内容存档于2022 01 04 外部連結 编辑Definition of Homoiconic at the C2 Wiki 页面存档备份 存于互联网档案馆 取自 https zh wikipedia org w index php title 同像性 amp oldid 74781751, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。