2012-02-21 47 views
4

在clojure中,兩個符號ab可能具有相同的名稱但元數據不同。符號然後是=但不是identical?在clojure中,何時定義幾個具有相同名稱但不同元數據的符號很有用?

例如:

(def a (with-meta 'cool {:real-name 'unknown})) 
(def b (with-meta 'cool {:real-name 'undefined})) 
(identical? a b); false 
(= a b); true 

這似乎是非常強大的。我希望看到這種語言功能的真實生活用例。

請分享您的原創想法。

+1

非原生的呢? – 2012-02-21 18:39:25

回答

3

這恐怕用例是豐富的思想,不是我的,但也許會感興趣:

語言本身使用此功能在def形式(和很方便的宏包裝def,包括defndefmacro ),因爲附加到命名創建的Vars符號的元數據將被轉移到Vars本身。它可以被編譯器和各種工具使用。

有人可能會指出defn &有限公司可能會選擇一個屬性映射參數,它被合併到Vars元數據中,所以從用戶的角度來看,不需要在符號名稱上使用元數據。但是,Plain def不會,並且內部defn將擴展爲def表單,其中元數據來自附加到Var名稱本身的屬性映射。 (爲了完整起見,在創建後可以在一個單獨的步驟中修改Var的元數據映射,但這不是defn中發生的情況。)

所有這一切都不會被程序員隱藏,通過方式。相反,將元數據附加到符號「手工」在許多情況下比使用屬性映射更簡潔(可能甚至可以說更多的慣用)。 Clojure的自己的標準庫使用這種風格(我的意思是,自舉後) - 例如,既clojure.coreclojure.string定義瓦爾命名replace,但只有後者被打上了返回值的類型(即String):

;;; clojure.core 
(defn replace 
    ...) 

;;; clojure.string 
(defn ^String replace 
    ...) 

^String此處轉換爲{:tag String},它在讀取時附加到符號replace,稍後由編譯器使用(作爲類型提示)。其他用途包括將Vars標記爲私有,^:private(在1.2中的Clojure 1.3,^{:private true}中),將文檔字符串附加到用普通的def創建的變量(1.2中唯一的方法; 1.3允許額外的文檔字符串參數,但^{:doc "..."}仍在使用中)等。

同樣,在ClojureScript中,你可能有兩個函數名爲foo,其中只有一個應該導出(當然,生活在不同的命名空間中)。在這種情況下,你會說

(defn ^:export foo ...) 

在一個命名空間和

(defn foo ...) 
在其他

; ^:export在讀取時被翻譯爲^{:export true},這將被合併到符號foo的出現的元數據中,然後由ClojureScript編譯器讀取並採取行動。

3

我在一些軟件中這樣做,我正在黑客做隨機過程的概率分析。你可以告訴我是否是「現實生活」。一般而言,元數據對於提供集合中獨立於其值的集合或元素的上下文很有用。例如,我可以想像一套通用的,這組實數,並和元素在實數載現在

(def Reals (with-meta 'Reals {:universe 'U})) 
(def x (with-meta 'x {:universe Reals})) 

,實數是不可數集,但我的元素可能包含它小得多的一套像有理數或整數。假設,我碰巧知道,通過一些額外的信息或作爲屬於整數其他一些分析某些元素的結果,而我用這個信息來分析一些元素,並添加遏制元

(def known-integers #{'x 'y 'z}) 
(defn find-known-integers [& s] (filter #(contains? known-integers %) (with-meta s {:universe 'Integers}))) 

我可以寫信

user=> (find-known-integers 'x 'a) 
(x) 

但我也有

user=> (= x (first (find-known-integers 'x 'a))) 
true 
user=> (identical? x (first (find-known-integers 'x 'a))) 
false 

,這樣即使兩個元素都有他們不認爲是相同的,因爲相同的值已知find-known-integers函數返回的版本包含在比原始版本更小的Universe中。當然,關於遏制的這種信息在某種意義上是「主觀的」,這就是爲什麼將它作爲元數據考慮是有用的,因爲不同的分析可能會產生變量的不同(甚至可能相互矛盾)結果。

2

注意identical?其實並不值+元數據,但參考比較的對象,所以identical?是同樣的事情,在Java中操作==。正因爲如此,你將有:

=> (def a 'sym) 
=> (def b 'sym) 
=> (= a b) 
true 
=> (identical? a b) 
false 

它可以區分不同的元數據變量用此方法(因爲內部,它們似乎是不同的對象),而不是相反:你不能推斷,與相同的元數據瓦爾將永遠是identical?

user=> (def d (with-meta 'sym { :a :b })) 
#'user/d 
user=> (def e (with-meta 'sym { :a :b })) 
#'user/e 
user=> (= d e) 
true 
user=> (identical? d e) 
false 
+0

我的問題更多地是關於這種語言功能的相關性。 – viebel 2012-02-22 08:40:20

相關問題