(-> x & forms)
Threads the expr through the forms. Inserts x as the second item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the second item in second form, etc.
;; Use of `->` (the "thread-first" macro) can help make code
;; more readable by removing nesting. It can be especially
;; useful when using host methods:
;; Arguably a bit cumbersome to read:
user=> (first (.split (.replace (.toUpperCase "a b c d") "A" "X") " "))
"X"
;; Perhaps easier to read:
user=> (-> "a b c d"
.toUpperCase
(.replace "A" "X")
(.split " ")
first)
"X"
;; It can also be useful for pulling values out of deeply-nested
;; data structures:
user=> (def person
{:name "Mark Volkmann"
:address {:street "644 Glen Summit"
:city "St. Charles"
:state "Missouri"
:zip 63304}
:employer {:name "Object Computing, Inc."
:address {:street "12140 Woodcrest Dr."
:city "Creve Coeur"
:state "Missouri"
:zip 63141}}})
user=> (-> person :employer :address :city)
"Creve Coeur"
;; same as above, but with more nesting
user=> (:city (:address (:employer person)))
"Creve Coeur"
;; Note that this operator (along with ->>) has at times been
;; referred to as a 'thrush' operator.
;; http://blog.fogus.me/2010/09/28/thrush-in-clojure-redux/
;; Your own REPL! (Read Eval Print Loop)
;; We would need a little helper macro for that
;; It does what its name says - loops forever
user=> (defmacro loop-forever [& body] `(loop [] ~@body (recur)))
;; Your own REPL
user=> (loop-forever (println (eval (read))))
(+ 1 2)
3
;; If you read the above code left to right (outside in) it reads LPER.
;; Inside out it reads REPL alright.
;; Sometimes it might be easier to read code outside in, just like a sequence of steps:
;; 1. Read, 2. Eval, 3. Print, 4. Loop
;; Here's how -> helps you:
user=> (-> (read) (eval) (println) (loop-forever))
(+ 1 2)
3
;; Does that read easier for you? If it does, -> is your friend!
;; To see what Clojure did behind the scenes with your -> expression:
user=> (require 'clojure.walk)
nil
user=> (clojure.walk/macroexpand-all '(-> (read) (eval) (println) (loop-forever)))
(loop* [] (println (eval (read))) (recur))
;; You can even use ->'s cousin ->> to setup your own REPL:
user=> (->> (read) (eval) (println) (while true))
(+ 1 2)
3
;; Can you see why we can't use -> to write the above?
user=> (def c 5)
user=> (-> c (+ 3) (/ 2) (- 1))
3
;; and if you are curious why
user=> (use 'clojure.walk)
user=> (macroexpand-all '(-> c (+ 3) (/ 2) (- 1)))
(- (/ (+ c 3) 2) 1)
;; simplest usage example, fill as second item in the first and second form
user=> (-> "foo"
(str "bar")
(str "zoo"))
"foobarzoo"
user=> (str "foo" "bar")
"foobar"
user=> (str (str "foo" "bar") "zoo")
"foobarzoo"
(-> 3 (- 2)) ; It means (- 3 2)
=> 1
(->> 3 (- 2)) ; It means (- 2 3)
=> -1
(doto 3 (- 2)) ; It means (- 3 2) but return the first object 3
=> 3
;; Be cautious with anonymous functions; they must be wrapped in an outer
;; pair of parens.
(-> 10
#(/ % 2))
;; will throw an exception, but
(-> 10
(#(/ % 2)))
;; will work fine. Similarly,
(-> 10
(fn [n] (/ n 2)))
;; will throw an exception, but
(-> 10
((fn [n] (/ n 2))))
;; works as intended.
;; How to thread functions that expect more than one argument
;; Say you want to thread this.
user=> (inc (/ 10 2))
=> 6
;; This obviously won't work
user=> (-> 2 10 / inc)
=> ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn
;; Since Clojure is expecting a function instead of `10` in `(10 2)`
user=> (clojure.walk/macroexpand-all '(-> 2 10 + inc))
=> (inc (+ (10 2)))
;; Instead you have two options, either just
user=> (-> (/ 10 2) inc)
=> 6
;; or
user=> (-> 10 (/ 2) inc)
=> 6
;; For large threads you can use commas (interpreted as whitespaces)
;; to visualize where the items are going to be inserted.
user=> (-> + (reduce 10 [6 4]) (* 5) (/ 100))
=> 1
;; with two commas (you can use one if you prefer)
user=> (-> + (reduce ,, 10 [6 4]) (* ,, 5) (/ ,, 100))
=> 1
;; For instance:
;; (reduce ,, 10 [6 4])
;; means
;; (reduce + 10 [6 4])
;; 4Clojure Question 38
(= (#(-> %&
sort
reverse
first) 1 8 3 4) 8)