R-E-P-L
Read-Eval-Print-Loop
Read: (read-string "(+ 1 2)") => '(+ 1 2)
Eval: (eval '(+ 1 2)) => 3
What if there's something in the middle?
(class (read-string "(+ 1 2)"))
;; clojure.lang.PersistentList
(map class (read-string "(+ 1 2)"))
;; (clojure.lang.Symbol java.lang.Long java.lang.Long)
(defn only-even!
[val]
(if (and (integer? val) (odd? val))
(inc val)
val))
(map only-even! (read-string "(+ 1 2)"))
;; '(+ 2 2)
(eval (map only-even! (read-string "(+ 1 2)")))
;; 4
Macros
Let's look at a real one.
(defmacro lazy-seq
"Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?"
{:added "1.0"}
[& body]
(list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))
;; simply returns a list, allocates a Java object (LazySeq) and wraps
;; your expressions in a function
(macroexpand-1 '(lazy-seq ANYTHING1 ANYTHING2))
;; '(new clojure.lang.LazySeq (fn* [] ANYTHING1 ANYTHING2))
Let's create an infinite sequence representing a square-wave
--__--__--__--__
(defn square-wave
"t is the period for a half-cycle"
[t]
(letfn
[(osc [cur-value so-far]
(let [so-far (mod so-far t)
next-val (if (zero? so-far)
(- cur-value)
cur-value)]
(cons next-val
(lazy-seq (osc next-val
(inc so-far))))))]
(osc 1 0)))
(take 10 (square-wave 3))
;; (-1 -1 -1 1 1 1 -1 -1 -1 1)
No mutable variables