This is my personal Clojure library. There came a point where I had to admit I just think about some things imperatively and fighting that is just wasting time.
(ns opar
"Owen's generic Clojure code that is not in any way project specific"
(:require [clojure.pprint]))
(defmacro imperative
"
This macro allows for blocks of imperative code. It behaves like an advanced (do) loop, where each argument is evaluated.
But to make matters more confusing, it supports 2 ternary options:
:< - Binds RHS to the symbol on the LHS
:? - If the first form is true, evaluate the (imperative) to the 2nd form.
For example:
(imperative
a :< '(1 2 3) ; Binds to a
(<= (count a) 3) :? nil ; Evaluates, because the test condition is true
(println \"I can also print\") ; If the test condition wasn't true, would print.
b :< (nth a 3) ; bind b
[a b]
)
"
[& forms]
(cond
; Can't be a ternary clause.
(< (count forms) 3) `(do ~@forms)
; LHS of a :< ternary clause
(= (second forms) :<) `(let [~(first forms) ~(nth forms 2)] (imperative ~@(nthrest forms 3)))
(= (second forms) :?) `(if ~(first forms) ~(nth forms 2) (imperative ~@(nthrest forms 3)))
; Not a ternary clause. (do) and recurse
:else `(do ~(first forms) (imperative ~@(rest forms)))
)
)
(def log-print (ref prn)) ;prn -> "1", 1 displayed differently
(dosync (ref-set log-print (fn [& args] (doall (map clojure.pprint/pprint args)))))
(dosync (ref-set log-print println))
(dosync (ref-set log-print prn))
(defn log [& args]
(apply @log-print args)
)