(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.

Reply via email to