如果您想自行操作,可以使用宏来扩展您自己的库中的语言。这是一种有限的途径,尽管它不会递归地遍历形式和完全替换 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}}