Skip to content

Instantly share code, notes, and snippets.

@Engelberg
Created May 26, 2016 22:45
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Engelberg/9fc1264f938077cf03eee112ebed1768 to your computer and use it in GitHub Desktop.
Save Engelberg/9fc1264f938077cf03eee112ebed1768 to your computer and use it in GitHub Desktop.
Better cond
(ns utils.cond
"A collection of variations on Clojure's core macros. Let's see which features
end up being useful."
{:author "Christophe Grand"}
(:refer-clojure :exclude [cond when-let if-let]))
(defmacro if-let
"A variation on if-let where all the exprs in the bindings vector must be true.
Also supports :let."
([bindings then]
`(if-let ~bindings ~then nil))
([bindings then else]
(if (seq bindings)
(if (= :let (bindings 0))
`(let ~(bindings 1)
(if-let ~(subvec bindings 2) ~then ~else))
`(let [test# ~(bindings 1)]
(if test#
(let [~(bindings 0) test#]
(if-let ~(subvec bindings 2) ~then ~else))
~else)))
then)))
(defmacro when-let
"A variation on when-let where all the exprs in the bindings vector must be true.
Also supports :let."
[bindings & body]
`(if-let ~bindings (do ~@body)))
(defmacro cond
"A variation on cond which sports let bindings and implicit else:
(cond
(odd? a) 1
:let [a (quot a 2)]
(odd? a) 2
3).
Also supports :when-let and binding vectors as test expressions."
[& clauses]
(when-let [[test expr & more-clauses] (seq clauses)]
(if (next clauses)
(if (= :let test)
`(let ~expr (cond ~@more-clauses))
(if (= :when test)
`(when ~expr (cond ~@more-clauses))
(if (= :when-let test)
`(when-let ~expr (cond ~@more-clauses))
(if (vector? test)
`(if-let ~test ~expr (cond ~@more-clauses))
`(if ~test ~expr (cond ~@more-clauses))))))
test)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment