my-let
, from Alex P., uses functions to implement a version of the Clojure special form let
:
(defmacro my-let
[bindings & body]
(assert (-> bindings count even?) "Bindings count can only be even.")
`((fn [~@(take-nth 2 bindings)]
~@body)
~@(take-nth 2 (rest bindings))))
This isn’t a complete implementation of let
, since it doesn’t allow bindings that depend on previous bindings, like in (let [a 1 b (inc a)] ...)
. And because it’s implemented in terms of functions, it also allows the let
to be a recur
target (just like loop
). It’s pretty cool how little code it takes to write a feature that can do this:
(my-let [{:keys [a b] :or {a :foo}} {:b 2}]
[a b])
;=> [:foo 2]
Leaning heavily on pre-existing language features can be a huge help.
Check out Alex’s nice and succinct explanation of the macroexpansion for more detail.