16

私はREPLで遊んでいて、奇妙な振る舞いをしました。

Clojure 1.4.0
user=> (type {:a 1})
clojure.lang.PersistentArrayMap
user=> (def x {:a 1})
#'user/x
user=> (type x)
clojure.lang.PersistentHashMap

すべての小さなリテラルマップはのインスタンスだと思いましたが、。PersistentArrayMapでバインドされている場合はそうではないようですdef。使用するdefと、Clojureが私のlitteマップに別の表現を選択するのはなぜですか?おそらく奇妙な実装の詳細に過ぎないことは知っていますが、興味があります。

4

1 に答える 1

15

この質問により、私は Clojure のソース コードを掘り下げました。これを理解するために、ソースに print ステートメントを入れるのに数時間を費やしました。

2 つのマップ式が異なるコード パスを介して評価されることがわかります

(type {:a 1})Java バイトコードを発行して実行します。出力されたコードは、小さなマップのPersistentArrayMapclojure.lang.RT.map()を返すマップを構築するために使用します。

static public IPersistentMap map(Object... init){
    if(init == null)
        return PersistentArrayMap.EMPTY;
    else if(init.length <= PersistentArrayMap.HASHTABLE_THRESHOLD)
        return PersistentArrayMap.createWithCheck(init);
    return PersistentHashMap.createWithCheck(init);
}

(def x {:a 1})少なくとも REPL から評価する場合、バイトコードは発行されません。定数マップはPersistentHashMapとして解析され、次のようにワープされclojure.lang.Compiler$MapExpr.parse()て返されますConstantExpr

else if(constant)
{
IPersistentMap m = PersistentHashMap.EMPTY;
for(int i=0;i<keyvals.length();i+= 2)
    {
    m = m.assoc(((LiteralExpr)keyvals.nth(i)).val(), ((LiteralExpr)keyvals.nth(i+1)).val());
    }
//System.err.println("Constant: " + m);
return new ConstantExpr(m);
}

評価されたときの式は、前述のようにPersistentHashMapである上で作成されdefた値をバインドします。ConstantExpr

では、なぜこのように実装されているのでしょうか。

知らない。単純な見落としであるか、PersistentArrayMap の最適化にそれほどの価値がない可能性があります。

于 2012-08-17T06:33:36.300 に答える