在計算機程式設計中，同像性（homoiconicity 來自希臘語單詞，homo 意為相同，icon 含義表像），是某些程式語言的特殊屬性，這意味著用此語言書寫的程式，可用使用這個語言將其作為資料來操縱，因此只要閱讀程式自身，就能推論出來這個程式的內部表示。該屬性經常被歸結成，這個語言將 程式碼當作 zhhans 資料；zhhant 資料。 簡介 在同像性程式語言中，程式的主要表示方式，也是屬於這個語言自身的原始型別的一種資料結構。這使得在這種語言中的超程式設計，比在沒有這個屬性的語言中要更加容易：在這種語言中的反射（在執行時檢查程式的實體），取決於單一的、同質的結構，而且它不必去處理以複雜語法形式出現的其它一些結構。同像性語言典型的包括對語法宏的完全支援，這允許程式設計者以簡明方式來表達程式變換。 Lisp 程式語言，是具有同像屬性的典型範例，它設計得易於進行列表操縱，而且其結構用具有巢狀列表形式的 S 表示式來給出，它可以由其他 LISP 程式碼來操縱。這類語言的其他例子有 Clojure（一種現代流行的 LISP 方言），Rebol 和，以及最近的 Julia 等程式語言。 歷史 同像性一詞的原始來源，是論文《編譯器語言的巨集指令擴充套件》。其依據是早期具影響力的論文《文字處理語言》： 艾倫凱在他 1969 年的博士論文中，使用並可能由此推廣了同像性這個術語： 用途及優點 同像性的一個優點是，向這個語言擴充套件新概念變得更加簡單，因為表示程式碼的資料，可在程式的元層和基礎層之間傳遞。函式的抽象語法樹，可以作為元層中的資料結構來合成和操縱，然後再被求值。它可以更容易理解如何操縱程式碼，因為它可以被理解為簡單的資料（因為語言本身的格式同於資料格式）。 同像性的典型演示是元迴圈求值器。 實作方法 所有範紐曼型架構的系統，其中包括絕大多數當今的通用計算機，由於原始機器程式碼在記憶體中的執行方式，其資料型別是位元組，故而可以隱含地描述為具有同像性。但是這個特徵也可以在程式語言層別上抽象出來。 Lisp 及其方言例如 Scheme，Clojure，Racket 等，使用 S 表示式來實現同像性。 其他被認為具有同像性的語言包括： Curl Elixir Io Julia Prolog R Rebol SNOBOL TclHomoiconic languages archived in true Blue blog at Oracle XSLT Rexx Wolfram 語言 同像性語言的程式設計範例 Lisp Lisp 使用 S 表示式作為資料和原始碼的外部表示。S 表示式可以用原始 Lisp 函式 READ 讀取。READ 返回 Lisp 資料：列表、符號、數字和字串。原始 Lisp 函式 EVAL 使用以資料形式表示的 Lisp 程式碼，計算副作用並得出返回結果。結果由原始 Lisp 函式 PRINT 打印出來，它從 Lisp 資料產生一個外部的 S 表示式。下面示例採用 Common Lisp 的 SBCL 實現。 以下 Lisp 示例，構造出的列表含有結構型別 person：它有兩個屬性 name 和 age，其型別分別是字串和整數： defstruct person name age PERSON personname cadr list makeperson name john age 20 makeperson name mary age 18 makeperson name alice age 22 mary 以下 Lisp 程式碼示例，使用了列表、符號和數值： sin 11 cos 203 中綴表示法為 sin 11cos 203 039501375 使用原始 Lisp 函式 LIST 產生上面的表示式，並將變數 EXPRESSION 設定為結果： defvar expression EXPRESSION setf expression list listsin 11 list cos 203 SIN 11 COS 203 Lisp 傳回並列印結果 third expression 表示式中的第三項 COS 203 將 COS 這項變更為 SIN： setf first third expression SIN SIN 變更之後的表示式為 SIN 11 SIN 203 求值表示式： eval expression 079888344 將表示式列印到字串： princtostring expression SIN 11 SIN 203 從字串中讀取表示式： readfromstring SIN 11 SIN 203 SIN 11 SIN 203 24 傳回一個其中有列表，數字和符號的列表 Prolog Prolog 是同像性語言並且提供了很多反射設施。 1 X is 25 X 10 2 L X is 25 write_canonical L is _ 2 5 L X is 25 3 L ten XX is 25 write_canonical L ten A is A 2 5 L ten XX is 25 4 L ten XX is 25 assert L L ten XX is 25 5 ten X X 10 6 在第 4 行建立一個新子句。算符 分隔一個子句的頭部和主體。透過 assert1 將它增加到現存的子句中，即增加它到 資料庫，這樣我們可以以後呼叫它。在其他語言中可以稱為 在執行時間建立一個函式。還可以使用 abolish1 或 retract1 從資料庫中移除子句。注意在子句名字後的數，是它可以接受的實際引數的數目，它也叫做元數。 我們可以查詢資料庫來得到一個子句的主體： 7 clause ten XY Y X is 25 8 clause ten XY Y X is Z Y X is 25 Z 25 9 clause ten XY call Y X 10 Y 10 is 25 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，並且使用近乎賦值的語法，可以進一步的將它指定為一個字的值，這種語法實際上可以被直譯器理解為特殊型別 setword，並採用一個字跟隨一個冒號的形式： block1 repeat i 3 print i hello 將這個塊的值賦值給字 block1 repeat i 3 print i hello type block1 求值字 block1 的型別 block 這個塊仍可以使用 Rebol 中提供的 do 函式來解釋，它類似於 Lisp 中的 eval。有可能審查塊的元素並變更它們的值，從而改變要求值程式碼的行為： block13 這個塊的第三個元素 3 block13 5 設定第三個元素的值為 5 5 probe block1 展示變更了的塊 repeat i 5 print i hello do block1 求值這個塊 1 hello 2 hello 3 hello 4 hello 5 hello 另見 標記法的認知維度，程式語言語法的設計原理。 串接程式語言。 面向語言程式設計。 符號式程式設計。 自修改程式碼。 LISP，同像性語言的可能最周知的例子。 超程式設計，對同像性非常有用的程式設計技術。 實化。 參考文獻 引用 外部連結 Definition of Homoiconic at the C2 Wiki Category 程式設計典範 Category 程式語言語義