On Fri, 27 Aug 2010 13:39:34 -0700 (PDT)
cej38 <junkerme...@gmail.com> wrote:

> I don't understand doto.

Apparently. The doc says:

user> (doc doto)
-------------------------
clojure.core/doto
([x & forms])
Macro
  Evaluates x then calls all of the methods and functions with the
  value of x supplied at the from of the given arguments.  The forms
  are evaluated in order.  Returns x.

  (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2))
nil

Ok, that's not very clear. I suspect that "from" is a typo for
"front". However, doto is a macro, so macroexpand-1 can help:

> Suppose I try the following:
> 
> user=> (doto 1 println)
> 1
> 1
> user=>

user> (macroexpand-1 '(doto 1 println))
(clojure.core/let [G__1967 1] (println G__1967) G__1967)

Reformatting:
(clojure.core/let [G__1967 1]
                  (println G__1967)
                  G__1967)

So it assigns the first argument to the generated variable G__1967,
then calls println on that variable, and finally returns it. Hence you
get two 1's printed.

> Now suppose I try the following:
> user=> (doto 1 #(println (inc %)))
> 1
> user=>

user> (macroexpand-1 '(doto 1 #(println (inc %))))
(clojure.core/let [G__1984 1] (fn* G__1984 [p1__1980] (println (inc p1__1980))) 
G__1984)

Reformatting:

(clojure.core/let [G__1984 1]
                  (fn* G__1984 [p1__1980] (println (inc p1__1980)))
                  G__1984)

fn* is an undocumented internal function returned by the #(...)
reader macro (not sure that's quite right for Clojure, but the effect
is the same). The doto macro rewrites that form to insert its first
argument at the front of the given arguments, in front of the argument
vector. fn* returns an function, without invoking it. That's
discarded, and the value of the first argument to the macro is
returned, as documented.

> But if I make the following definition:
> (defn some-function [x]
>     (println (inc x)))
> 
> user=> (doto 1 some-function)
> 2
> 1
> user=>

user> (macroexpand-1 '(doto 1 some-function))
(clojure.core/let [G__2012 1] (some-function G__2012) G__2012)

This mimics the first form - the symbol that is the "forms" argument
is wrapped in a list and the first argument inserted as it's first
argument.

> Why did #(println (inc %)) not work and some-function work?

Because you didn't invoke the function returned by #(println (inc
%). Doto treats the (fn* ...) the way it treats all lists, not the way
it treats symbols, which is wrong in this case.  If you invoke that
function without arguments, then the doto macro will correctly insert
it's first argument into the call:

user> (doto 1 (#(println (inc %))))
2
1
user> (macroexpand-1 '(doto 1 (#(println (inc %)))))
(clojure.core/let [G__2046 1] ((fn* [p1__2042] (println (inc p1__2042))) 
G__2046) G__2046)

Reformatting again:

(clojure.core/let [G__2046 1]
                  ((fn* [p1__2042] (println (inc p1__2042))) G__2046)
                  G__2046)

It's a little clearer if you use (fn instead of #(, since that leaves
your function intact, but has the same problem:

user> (doto 1 (fn [x] (println(inc x))))
1
user> (macroexpand-1 '(doto 1 (fn [x] (println(inc x)))))
(clojure.core/let [G__2103 1] (fn G__2103 [x] (println (inc x))) G__2103)

or:

(clojure.core/let [G__2103 1]
                  (fn G__2103 [x] (println (inc x)))
                  G__2103)

vs:

user> (doto 1 ((fn [x] (println(inc x)))))
2
1
user> (macroexpand-1 '(doto 1 ((fn [x] (println(inc x))))))
(clojure.core/let [G__2123 1] ((fn [x] (println (inc x))) G__2123) G__2123)

or

(clojure.core/let [G__2123 1]
                  ((fn [x] (println (inc x))) G__2123)
                  G__2123)

  <mike
-- 
Mike Meyer <m...@mired.org>             http://www.mired.org/consulting.html
Independent Network/Unix/Perforce consultant, email for more information.

O< ascii ribbon campaign - stop html mail - www.asciiribbon.org

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to