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

Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to