如果你自己想这么做,你可以使用宏来扩展你自己的库中的语言。这是一种有限的方法,尽管它不是递归遍历形式并完全替换 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}}