Clojure Programming/Examples/API Examples/Macros

-> edit

This is the "threading" operator.

(macroexpand-1 '(-> true (if "clojure")))
=>(if true "clojure")

this:

user=> (-> "abc" .toUpperCase ,, (.replace ,, "B" "-"))
"A-C"

is equivalent to:

user=> (.replace (.toUpperCase "abc") "B" "-")
"A-C"

NOTE: you do not need to insert ',,', since clojure treats them like whitespace, but marking the forms second position this way enhances readability.

However -> works on everything

user=> (-> true (if ,, inc dec) (map ,, [1 2 3]))
(2 3 4)

or expanded

  (map (if true inc dec) [1 2 3])

So one can also use macros and normal functions in ->, i.e. non-methods.

Here is an example that should make every devoted Programmer fall in love with lisp, if he compares it with equivalent Java code. Reading the name of the first entry in a zip file:

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

cond edit

user=> (cond false 1 true 2)
2
user=> (cond nil 1 2 3)
3

condp edit

(let [a 5]
  (condp = a
    1 "hi"
    5 "fun"))
-> "fun"

The test expression (1 and 5 in the above example) is inserted as first parameter to the predicate function, the comparison expression (here a) as second. condp throws an java.lang.IllegalArgumentException if no clauses are matched in the above example. condp also allows to add a single default expression after the clauses whose value will be returned if no clauses matches.

(let [a 7]
  (condp = a
    1 "hi"
    5 "fun"
    "no match"))
-> "no match"