Hi, Am 05.01.2009 um 18:35 schrieb wubbie:
This example is from clojure site. My question is on line 5 and line 6: The confusion is str is a function and here looks like used as a regular variable. Thanks in advance.
binding can be used to temporarily assign a different value to a global Var. Let's understand the example line by line.
(defn loves [x y] (str x " loves " y))
First we define a function "loves" which uses the standard str function to concate it's arguments. So far easy to understand.
(defn test-rebind [] (println (loves "ricky" "lucy"))
Here we do a proof of concept and show that our function "loves" works as expected. Output:
ricky loves lucy
Now to nitty-gritty:
(let [str-orig str] ---> line 5:
First we save the original str function in a local.
(binding [str (fn [& args] --> line 6: (println "Logging str") (apply str-orig args))] -->line 8:
Now we use binding to replace the global str function with another one, which we define using the original str function. We log, that we called our modified function and the just delegate all arguments to the original str function, which we saved in str-orig. This modified str is only available inside the body of the binding form. We leave it by reaching the end of the body or throwing an exception, the original str is again restored. Also other threads also don't see the modified str. This is really restricted to the body of the binding. Now we call again our initial function "loves". Please note: we did not modify our function in any way.
(println (loves "fred" "ethel")))))
See the output:
Logging str Logging str Logging str Logging str Logging str fred loves ethel
Huh? So although we did not modify our "loves" function we get a different output? Why is that. The solution is binding. The loves function is called *inside* the binding body and although it is defined *outside* the binding, it will use the modified str function. So you are right the binding looks similar to a let. (binding [str ...] ...) vs. (let [str ...] ...) However the let introduces a new "str" which *shadows* the global str function and is only visible for the code in the let. In particular functions called inside the let will see the str which was in effect when they were defined. The binding however *replaces* the str which was in effect, when the function was defined. Of course this works only with global Vars and not with locals as introduced by let. (Note: the number of "Logging"s depends on the implementation of the str function.) Hope this helps. Sincerely Meikel
smime.p7s
Description: S/MIME cryptographic signature