(defn gen-pvec [pb] (fn [bvec b val] (let [gvec (gensym "vec__") gseq (gensym "seq__") gfirst (gensym "first__") has-rest (some #{'&} b)] (loop [ret (let [ret (conj bvec gvec val)] (if has-rest (conj ret gseq (list `seq gvec)) ret)) n 0 bs b seen-rest? false] (if (seq bs) (let [firstb (first bs)] (cond (= firstb '&) (recur (pb ret (second bs) gseq) n (nnext bs) true) (= firstb :as) (pb ret (second bs) gvec) :else (if seen-rest? (throw (new Exception "Unsupported binding form, only :as can follow & parameter")) (recur (pb (if has-rest (conj ret gfirst `(first ~gseq) gseq `(next ~gseq)) ret) firstb (if has-rest gfirst (list `nth gvec n nil))) (inc n) (next bs) seen-rest?)))) ret)))) ) (defn gen-bes [b] (let [transforms (reduce1 (fn [transforms mk] (if (keyword? mk) (let [mkns (namespace mk) mkn (name mk)] (cond (= mkn "keys") (assoc transforms mk #(keyword (or mkns (namespace %)) (name %))) (= mkn "syms") (assoc transforms mk #(list `quote (symbol (or mkns (namespace %)) (name %)))) (= mkn "strs") (assoc transforms mk str) :else transforms)) transforms)) {} (keys b))] (reduce1 (fn [bes entry] (reduce1 #(assoc %1 %2 ((val entry) %2)) (dissoc bes (key entry)) ((key entry) bes))) (dissoc b :as :or) transforms)) ) (defn gen-pmap [pb] (fn [bvec b v] (let [gmap (gensym "map__") gmapseq (with-meta gmap {:tag 'clojure.lang.ISeq}) defaults (:or b)] (loop [ret (-> bvec (conj gmap) (conj v) (conj gmap) (conj `(if (seq? ~gmap) (clojure.lang.PersistentHashMap/create (seq ~gmapseq)) ~gmap)) ((fn [ret] (if (:as b) (conj ret (:as b) gmap) ret)))) bes (gen-bes b)] (if (seq bes) (let [bb (key (first bes)) bk (val (first bes)) local (if (instance? clojure.lang.Named bb) (with-meta (symbol nil (name bb)) (meta bb)) bb) bv (if (contains? defaults local) (list `get gmap bk (defaults local)) (list `get gmap bk))] (recur (if (ident? bb) (-> ret (conj local bv)) (pb ret bb bv)) (next bes))) ret)))) ) (defn pb [] (fn pb [bvec b v] (let [pvec (gen-pvec pb) pmap (gen-pmap pb)] (cond (symbol? b) (-> bvec (conj b) (conj v)) (vector? b) (pvec bvec b v) (map? b) (pmap bvec b v) :else (throw (new Exception (str "Unsupported binding form: " b)))))) ) (defn destructure [bindings] (let [bents (partition 2 bindings) pb (pb) process-entry (fn [bvec b] (pb bvec (first b) (second b)))] (if (every? symbol? (map first bents)) bindings (reduce1 process-entry [] bents))))
(fact "重构clojure destructure" :destructure (destructure '[a 3]) => '[a 3] (destructure '[[a b] ["a" "b"]]) => 2 ) the refactor clojure.core/destructure It's a bit big function. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.