2012-02-21 9 views
4

クロージャでは、2つの記号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

ユニークではないものはどうなりますか? –

答えて

3

私はこのユースケースは、リッチのアイデアではなく私のものですが、おそらくそれは対象としています怖い:

言語自体がdefndefmacro含むdefを包むdefフォーム(と便利なマクロ、でこの機能を使用しています)、作成されているVarsを表すシンボルに付けられたメタデータがVars自身に転送されるためです。これは、コンパイラとさまざまなツールで使用できます。

defn & Coordinatesはオプションで、Varsメタデータにマージされる属性マップ引数を取ることがあるので、ユーザーの視点から記号名のメタデータを使用する必要はありません。しかし、プレーンdefは、そうではなく、内部ではdefndefフォームに展開され、メタデータはVar名自体にアタッチされたアトリビュートマップから取得されます。 (完全性のために、Varのメタデータマップを作成した後に別のステップで変更することは可能ですが、defnでは起こりません)

これはプログラマからは全く隠されていません。道。反対に、メタデータを「手で」シンボルに付けることは、多くの場合、属性マップを使用するよりも簡潔です(多分もっと慣用的なこともあります)。 Clojureは独自の標準ライブラリには、このスタイルを使用しています(と私はポストブートストラップを意味する) - 例えば、clojure.coreclojure.stringの両方がバールを定義replaceの名前が、後者のみが戻り値の型(すなわちString)でタグ付けされています

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

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

^Stringここでは{:tag String}に変換されます。これは、読み取り時にシンボルreplaceに付けられ、後でコンパイラによって(タイプヒントとして)使用されます。その他の用途としては、^:private(1.2ではClojure 1.3,^{:private true})のプライベートとしてVarsをマークし、平文defで作成したVarsにドキュメントストリングを添付します(1.2:1.3ではそれを行う唯一の方法は余分なdocstring引数を与えますが、まだ^{:doc "..."}が使用されています)など

同様に、ClojureScriptでは、fooの2つの関数だけをエクスポートすることができます(もちろん、別の名前空間に存在する)。その場合、あなたは他の中

(defn ^:export foo ...) 
1つの名前空間に

(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関数によって返されるバージョンは、オリジナルよりはるかに小さい宇宙に含まれることが知られています。もちろん、封じ込めに関するこの情報はある意味では「主観的」なので、メタデータとして考えることは有用です。なぜなら、さまざまな分析が変数に対して異なる結果をもたらすからです。

2

実際にidentical?は値+メタデータではなくオブジェクトへの参照を比較するので、identical?はJavaの演算子==と同じものです。このため、あなたが持っているでしょう:

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

(内部的に、彼らは別のオブジェクトのように見えるため)この方法では異なるメタデータと変数を区別することが可能ですが、その逆はない:あなたが推測することができないが、同じメタデータとvarsは常に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

関連する問題