Created
March 27, 2020 16:12
-
-
Save acobster/6e19f35ac3eb9dfb8aac725c0463f364 to your computer and use it in GitHub Desktop.
Macro examples
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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