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