2016-04-18 8 views
1

:nameのようなキーワードまたは[:person :name]のようなキーワードになる関数の引数をサポートするためのClojureのきれいな方法は、Clojureの呼び出しで使用できるようにするgetまたはget-inClojure fnのget-inのキーワードまたはパス引数のサポート

今私は(get-in m (flatten [path]))を入力しています。pathが入力されています。これは動作しますが、頻繁に使用するために遅くなったり、大量のデータが集まったりしているように思えます。私はベンチマークを行っていません。

代わりに、私は私がgetまたはget-inを使用する(coll? path)に派遣ことができると思います:それは、より効率的であるかもしれないよう

(let [path [:person :name] 
     m {:person {:name "John Smith"}}] 
    (if (coll? path) 
    (get-in m path) 
    (get m path))) 
=> {:name "John Smith"} 

は思えます。

答えて

2

実際に発信者がキーワードまたはのいずれかを渡すことができるようにするには、これは完全に正当な方法です。私はおそらく、coll?の代わりにkeyword?をテストとして使用します。 coll?は、(入力がベクトルまたはシーケンスの代わりにマップである場合など)いくつかの偽陽性を示しますが、keyword?はそうではありません。

(let [m {:person {:name "John Smith"}}] 
     path [:person :name] 
    (if (keyword? path) 
    (get m path) 
    (get-in m path))) 
;=> "John Smith" 

もう一つの方法は、あなたが完全に条件を避けるためにできるようになる単に機能などの入力を処理することができます

(let [m {:person {:name "John Smith"}} 
     f (comp :name :person)] 
    (f m)) 
;=> "John Smith" 

これは単なるキーワードまたはのシーケンスほど素敵ではありませんただし、呼び出し元がマップに到達するだけの任意の関数を渡すことができれば、問題が発生する可能性があります。

しかし、この場合の最適なオプションは、ユーザーにシーケンスを渡し、常にget-inを使用させることです。これは、このような条件付きの複雑さを回避し、さらに一般的なマップを可能にします。この例を考えてみます。

(let [m {[:foo :bar] "John Smith" 
     :foo {:bar "John Cena"}} 
     path [:foo :bar]] 
    (if (coll? path) 
    (get-in m path) 
    (get m path))) 
;=> "John Cena" 

この場合、pathは完全にあいまいです。発信者が本当にが欲しいものを特定する方法はありません。あなたの地図のすべてのキーがキーワードであるなら、それは完璧です。この問題に対処する必要はありません。しかし、暗黙のコンバージョンを追加すると、潜在的に足で自分自身を撃つことが可能になることが示されています。

+0

あいまいさについての良い点。別のオプションは、korksをサポートすることです。 '(my-fn [:foo:bar])'と '(my-fn:foo:bar)'の両方をサポートする '[&path]'として解析される ''(my-fn:some:path) 。 –

+0

@pate可変引数を使うことができれば、是非それをしてください。基本的には、シーケンスを渡すための構文的な砂糖ですが、ここではあいまいさがありません。 –

+0

'(get-in m [[:foo:bar]:more:bars])'、no( '' foo:bar:more:bar) ''という結果になる ' ? –

関連する問題