如果你想自己实现,可以在自己的库中使用宏来扩展语言。这是一种有限的方法,尽管它不会递归遍历形式并且完整地替换 let
;如果你想要启用 :rest 表单,你将不得不用它代替 let。有使用宏工具(如 macrolet 和其他工具)进行代码遍历和扩展的方法,但这需要读者自己练习。质量保证告知我,他们没有时间来测试除了所见直接的 repl 输出之外的内容,所以请注意用户风险。
(defmacro fancy-let [bindings & body]
(let [binds (partition-all 2 bindings)
_ (assert (every? #(= 2 (count %)) binds) "binding form must be even yo!")]
`(let [~@(->> (for [[l r :as b] binds]
(if (and (map? l)
(l :rest)
(or (l :keys) (l :syms) (l :strs)))
(let [ks (l :keys)
strs (l :strs)
syms (l :syms)
remaining (l :rest)
selected (concat (map keyword ks)
(map name strs)
(for [s syms]
`(quote ~s)))
symb (gensym "the-map")]
[symb r
(dissoc l :rest) symb
remaining `(dissoc ~symb ~@selected)])
b))
(reduce (fn [acc xs] (apply conj acc xs)) []))]
~@body)))
user> (fancy-let [{:keys [a] :strs [name age] :syms [origin] :rest m}
{:a 1 :b 2 :c 3 "name" "bilbo" "age" 200 'origin :shire}]
{:a a :name name :age age :origin origin :remaining m})
{:a 1, :name "bilbo", :age 200, :origin :shire, :remaining {:b 2, :c 3}}