如果你想自己实现,你可以在自己的库中使用宏来扩展语言。这是一种有限的方式,虽然它不会递归遍历形式和完全替换 let
;如果你想启用 :rest 表单,你必须用它来代替 let。有一些方法可以代码遍历和利用宏工具(如 macrolet 及其他工具)来实现,但这是读者练习的一部分。质量保证通知我说,他们没有时间在外部测试,所以他们提醒用户注意。
(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}}