tags:

views:

249

answers:

3

It seems to be a powerful macro, yet I'm failing to apply it to anything but silly examples. Can you show me some real use of it?

Thanks!

+8  A: 

Compare:

user> (:baz (:bar (:foo {:foo {:bar {:baz 123}}})))
123
user> (java.io.BufferedReader. (java.io.FileReader. "foo.txt"))
#<BufferedReader java.io.BufferedReader@6e1f8f>
user> (vec (reverse (.split (.replaceAll (.toLowerCase "FOO,BAR,BAZ") "b" "x") ",")))
["xaz" "xar" "foo"]

to:

user> (-> {:foo {:bar {:baz 123}}} :foo :bar :baz)
123
user> (-> "foo.txt" java.io.FileReader. java.io.BufferedReader.)
#<BufferedReader java.io.BufferedReader@7a6c34>
user> (-> "FOO,BAR,BAZ" .toLowerCase (.replaceAll "b" "x") (.split ",") reverse vec)
["xaz" "xar" "foo"]

-> is used when you want a concise way to nest calls. It lets you list the calls in the order they'll be called rather than inside-out, which can be more readable. In the third example, notice how much distance is between some of the arguments and the function they belong to; -> lets you group arguments and function calls a bit more cleanly. Because it's a macro it also works for Java calls, which is nice.

-> isn't that powerful, it just saves you a few parens now and then. Using it or not is a question of style and readability.

Look at the bottom of clojure.zip for extreme examples of how this is helpful.

(-> dz next next next next next next next next next remove up (append-child 'e) root)
Brian Carper
+5  A: 

Taken from the wiki I've always found this example impressive:

user=> (import '(java.net URL) '(java.util.zip ZipInputStream))
user=> (-> "http://clojure.googlecode.com/files/clojure_20081217.zip"
           URL. .openStream ZipInputStream. .getNextEntry bean :name)

As Brian said - it isn't 'useful' so much as 'different style'. I find for all java interop this form of 'start with X' then do Y and Z ... more readable than do Z to Y of X.

Basically you have 4 options:

; imperative style named steps:
(let [X something
      b (Y X)
      c (Z b)] c)

; nested calls
(Z (Y X))

; threaded calls
(-> X Y Z)

; functional composition
((comp Z Y) X)

I find -> really shines for java interop but avoid it elsewhere.

Timothy Pratley
+2  A: 
(defn search-tickets-for [term]
  (-> term search zip-soup first :content
    ((partial filter #(= :body (:tag %)))) first :content
    ((partial filter #(= :div (:tag %))))
    ((partial filter #(= "content" ((comp :id :attrs) %))))
    ((partial map :content)) first ((partial map :content))
    ((partial map first)) ((partial filter #(= :ul (:tag %)))) first :content
    ((partial map :content))
    ((partial map first))
    ((partial mapcat :content))
    ((partial filter #(= :h4 (:tag %))))
    ((partial mapcat :content))
    ((partial filter #(= :a (:tag %))))
    ((partial mapcat :content))))

clojurebot from #clojure uses this to search assembla tickets

hiredman