8

参照を確認しました:http ://clojure.org/vars#Vars%20and%20the%20Global%20Environment、http : //clojuredocs.org/clojure_core/clojure.core/binding

clojureと^:dynamicおよびClojureDynamicBindingと同様に

binding私が書いたすべてのプログラムにはそれらがなく、従来の方法で例を書く方法を見つけることができるので、なぜ必要なのかまだわかりません-私はより理解しやすいと思います。これを利用したプロジェクト/プログラミングパラダイムの例はありますか?

たとえば...動物を話す例では、次のようにして同様の効果を得ることができます。

(def dog {:name "Dog" :sound "Woof"})
(def cat {:name "Cat" :sound "Meow"})

(defn speak [animal]
   (str (:name animal) " says " (:sound animal))

(println (speak dog))
(println (speak cat))

マクロも動的バインディングもありません...それでも非常にクリーンです。

4

2 に答える 2

15

それらは厳密には必要ありません。当然のことながら、がなくても好きなことを実行できます。binding実際にbinding存在しない場合は、マクロとJavaを使用して比較的簡単に再実装できますThreadLocal

ただし、バインディングは、パラメーターを明示的に渡す必要なしに、動的コンテキストを関数に渡す方法として役立ちます。

深くネストされた高階関数を作成していて、内部に埋め込まれている低レベルの関数に値を渡すために、呼び出しスタック内のすべての関数にパラメーターを追加したくない場合に特に便利です。

あなたの例に基づいて構築するには:

(def ^:dynamic *loud-noises* false)

(defn speak [animal]
     (str (:name animal) " says " 
          (let [sound (:sound animal)]
            (if *loud-noises* (.toUpperCase sound) sound))))

(speak dog)
=> "Dog says Woof"

(binding [*loud-noises* true]
  (speak dog))
=> "Dog says WOOF"

speak別の動作を取得するために、関数にパラメーターを追加する必要がないことに注意してください。この場合、パラメーターを追加するのは簡単ですが、speak関数が複雑な高階関数の奥深くに埋め込まれていると想像してみてください。

それでも、全体として最善のアドバイスは、本当に必要でない限り、動的バインディングを避けることだと思います。可能であれば、通常は明示的なパラメーターを追加することをお勧めします。直接パラメーターを使用すると、関数のテストと推論が容易になります。

于 2012-10-17T12:27:49.833 に答える
1

上記のmikeraの例をフォローアップするだけです。なぜ表現力の低い言語でそれを行うのかはわかりますが、clojureは表現力が非常に高いため、書き直したいと思います...loud-noise関数を少し変更して、同じ効果を得ることができます。話すための追加のパラメータを追加することによって...

(defn speak [animal & opts]
  (let [sound (:sound animal)
        sound (if (some #(= % :louder) opts)
                 (.toUpperCase sound) sound)]
    (str (:name animal) " says " sound)))


> (speak dog)
;;=> "Dog says Woof"
> (speak dog :louder)
;;=> "Dog says WOOF"

元のコードを変更できない場合、バインディングは迅速で汚いソリューションをハックする方法にすぎませんか?

于 2012-10-18T00:36:36.657 に答える