Macros are Fun!



Macros are Fun!

0 1


bohclojure.macros

macros talk

On Github gtrak / bohclojure.macros

Macros are Fun!

Created by Gary Trakhman

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

Resources

Thanks!