Clojure

評估

評估可以在許多情況下發生

  • 互動式,在 REPL 中

  • 在從串流讀取的表格序列中,透過 load / load-file / load-reader / load-string

  • 透過程式設計,透過 eval

Clojure 程式由表達式組成。編譯器會將每個未由特殊形式或巨集特別處理的表格視為表達式,並評估以產生值。沒有宣告或陳述,儘管有時可能會評估表達式以產生副作用並忽略其值。在所有情況下,評估都是相同的 - 編譯器會考慮單一物件,進行評估,並傳回其結果。如果需要編譯表達式,就會進行編譯。沒有單獨的編譯步驟,也不必擔心您定義的函式正在被解釋。Clojure 沒有解釋器

字串、數字、字元、truefalsenil 和關鍵字會評估為它們自己。

符號會解析

  • 如果符號具有命名空間限定,則其值為符號所命名的全域變數繫結值。如果沒有符號所命名的全域變數,或者符號所指為不同命名空間中的非公開變數,則會發生錯誤。

  • 如果符號具有套件限定,則其值為符號所命名的 Java 類別。如果沒有符號所命名的類別,則會發生錯誤。

  • 否則,符號沒有限定,且下列第一個條件適用

    1. 如果符號命名特殊形式,則會視為特殊形式,且必須相應使用。

    2. 如果在區域範圍內(例如在函式定義或 let 形式中),則會進行查詢,以查看符號是否命名區域繫結(例如函式引數或 let 繫結名稱)。如果是,則其值為區域繫結的值。

    3. 在目前命名空間中進行查詢,以查看符號與類別之間是否有對應。如果是,則符號會視為命名 Java 類別物件。請注意,類別名稱通常表示類別物件,但在某些特殊形式中會以特殊方式處理,例如 .new

    4. 在目前命名空間中進行查詢,以查看符號與變數之間是否有對應。如果是,則其值為符號所指變數繫結的值。

    5. 這是一個錯誤。

如果符號具有元資料,編譯器可能會使用它,但它不會是結果值的一部分。

向量、集合和映射會產生向量和(雜湊)集合和映射,其內容是它們所包含物件的評估值。向量元素從左到右評估,集合和映射會以未定義的順序評估。元資料映射也是如此。如果向量或映射具有元資料,則評估後的元資料映射將成為結果值的元資料。

user=> (def x 1)
user=> (def y 2)
user=> ^{:x x} [x y 3]
^{:x 1} [1 2 3]

空清單 () 會評估為空清單。

非空清單會視為對特殊形式、巨集或函式的呼叫。呼叫的形式為 (運算子 運算元*)。

特殊形式是內建於 Clojure 的基本元件,可執行核心運算。如果呼叫的運算子是解析為特殊形式名稱的符號,則呼叫會對應到該特殊形式。每個形式都個別在 特殊形式 中討論。

巨集 是用於處理形式的函式,允許語法抽象。如果呼叫的運算子是命名為巨集函式的全域變數符號,則會呼叫該巨集函式,並將未評估的運算元形式傳遞給它。然後,巨集的傳回值會在它的位置評估。

如果運算子不是特殊形式或巨集,呼叫會被視為函式呼叫。運算子與運算元(如果有的話)會從左到右進行評估。運算子評估的結果會轉換成 IFn(代表 Clojure 函式的介面),並呼叫其 invoke(),傳遞已評估的引數。invoke() 的傳回值是呼叫表達式的值。如果函式呼叫形式有元資料,編譯器可能會使用它,但它不會是結果值的一部分。請注意,特殊形式和巨集可能會對其引數進行非正常的評估,如其在 特殊形式 條目中所述。

上述未討論的任何物件都會評估為其本身。


(load classpath-resource …​)
(load-file filename)
(load-reader reader)
(load-string string)

上述說明了單一形式的評估。各種載入形式會依序讀取和評估來源中包含的各種形式。這些形式通常有副作用,通常會影響全域環境,定義函式等。

載入函式會在暫時性的內容中執行,其中 *ns* 有新的繫結。這表示如果任何形式對該變數有影響(例如 in-namespace),影響會在載入完成時解除。load 等會傳回最後一個表達式產生的值。


(eval form)

評估形式 資料結構(不是文字!)並傳回結果。

(eval (list + 1 2 3))
-> 6