Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@acobster
Created March 27, 2020 16:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save acobster/6e19f35ac3eb9dfb8aac725c0463f364 to your computer and use it in GitHub Desktop.
Save acobster/6e19f35ac3eb9dfb8aac725c0463f364 to your computer and use it in GitHub Desktop.
Macro examples
(ns macro-playground.core)
(defmacro square [x]
`(let [x# ~x]
(* x# x#)))
(comment
;; Example expansions for the when* macro:
(when* (even? x) (println "EVEN"))
; expands to...
(if (even? x) (println "EVEN") nil)
(when* (even? x) (println "EVEN") x)
; expands to...
(if (even? x) (do (println "EVEN") x) nil))
(defmacro when* [test & body]
`(if ~test
(do
~@body
)
nil))
(comment
;; Example expansions for the while* macro
(while* (> @x 0) (swap! x dec))
; expands to...
((loop [] (when (> @x 0) (swap! x dec) (recur)))))
(defmacro while* [test action]
`(loop []
(when ~test ~action (recur))))
(comment
;; Example regex macro expansions:
(regex #"abc" "abc"
(println %0)
(println %1))
; expands to...
(let [match (re-find #"abc" "abc")]
(when match
(let [[%0 %1 %2 %3 %4 %5 %6 %7 %8 %9] match]
(println %0)
(println %1))))
(regex #"a(bc)" "abc"
(println %0)
(println %1))
; expands to...
(let [match (re-find #"a(bc)" "abc")]
(when match
(let [[%0 %1 %2 %3 %4 %5 %6 %7 %8 %9] match]
(println %0)
(println %1)))))
(defmacro regex [pattern haystack & body]
`(let [match# (re-find ~pattern ~haystack)]
(when match#
(let [[~'%0 ~'%1 ~'%2 ~'%3 ~'%4 ~'%5 ~'%6 ~'%7 ~'%8 ~'%9]
(if (string? match#) [match#] match#)]
~@body))))
(comment
;; Example expansions of the with-open* macro
(with-open*
[in (clojure.java.io/input-stream (clojure.java.io/file "/tmp/test.txt"))]
(println (slurp in)))
; expands to...
(let [in (clojure.java.io/input-stream (clojure.java.io/file "/tmp/test.txt"))]
(try
(println (slurp in))
(finally
(.close in))))
;; With multiple files
(with-open*
[in1 (clojure.java.io/input-stream (clojure.java.io/file "/tmp/test.txt"))
in2 (clojure.java.io/input-stream (clojure.java.io/file "/tmp/test2.txt"))]
(println (slurp in1))
(println (slurp in2)))
; expands to...
(let [in1 (clojure.java.io/input-stream (clojure.java.io/file "/tmp/test.txt"))
in2 (clojure.java.io/input-stream (clojure.java.io/file "/tmp/test2.txt"))]
(try
(println (slurp in1))
(println (slurp in2))
(finally
(.close in2)
(.close in1)))))
(defmacro with-open* [bindings & body]
; compile time stuff!
; get the list of bindings to the files we need to close at the end
(let [close-ins (map
#(list '.close %)
; we want to close any files we open *in reverse order*
(reverse (take-nth 2 bindings)))]
; runtime!
; throw everyohing inside a try,
; close the files *in reverse order* in the finally
`(let ~bindings
(try
~@body
(finally
~@close-ins)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment