what is the practical purpose of clojure's dynamic vars and binding?

时光总嘲笑我的痴心妄想 提交于 2019-12-04 03:59:06

There isn't strictly a need for them: as you rightly observe you can do anything you like without binding, and indeed if binding didn't exist then you could re-implement it relatively easily using macros and Java's ThreadLocals.

Binding is however useful as a way of passing dynamic context to a function without needing to explicitly pass a parameter.

It is particularly useful when you are composing deeply nested higher order functions and don't want to add extra parameters to every single function in the call stack in order to pass some value to the lower level functions embedded deep within.

To build on your example:

(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"

Note I didn't need to add an extra parameter to the speak function to get different behaviour. Adding an extra parameter would be trivial in this case, but imagine if the speak function was buried deep within a complex higher order function.....

Still, I think the best advice overall is to avoid dynamic binding unless you really need it. It is usually better to add explicit parameters if you can: direct parameters make it easier to test and reason about functions.

Just following up on mikera's example above.. I can see why you would do it in a less expressive language but because clojure is so expressive, I would rather rewrite it... The loud-noise function can be changed slightly, again to achieve the same effect by adding additional parameters to speak...

(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"

Is binding just a way to hack up a quick and dirty solution if you can't change the original code?

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!