On Sun, Aug 24, 2008 at 6:02 PM, budu <[EMAIL PROTECTED]> wrote:
>
> Well, for now only the value s used by the parser macro is really
> needed.

I think you misunderstood me, but I'm not too sure.  Anyway, here's an attempt:

(defn match-forms [p s]
  (if (= '_ p) []
    (loop [p p s s vars []]
      (cond
        (and (= 0 (count p)) (= 0 (count s))) vars
        (= 0 (count s)) nil
        :else (let [[fp & rp] p [fs & rs] s]
                (cond
                  ;; wildcard pattern
                  (= '_ fp) (recur rp rs vars)
                  ;; rest
                  (and (symbol? fp) (= '& fp))
                  (conj vars (first rp) (conj rs fs))
                  ;; add variable to bindings
                  (symbol? fp) (recur rp rs (conj vars fp fs))
                  ;; match a symbol
                  (and (seq? fp) (= 'quote (first fp)))
                  (if (= fs (second fp)) (recur rp rs vars) nil)
                  ;; not matching
                  true nil))))))

(defmacro match [value & clauses]
  (when (and clauses (= 0 (rem (count clauses) 2)))
    (let [[c1 c2 & cr] clauses
          syms (take-nth 2 (match-forms c1 c1))]
      `(if-let m# (take-nth 2 (rest (match-forms '~c1 ~value)))
         (let [~(vec syms) (vec m#)]
           ~c2)
         (match ~value [EMAIL PROTECTED])))))

The trick here is I run match-forms once at compile time to get the
list of symbols that will need to be bound, even though I don't have
the real values yet.  I use that list to set up a "let" expression.
At runtime, I run match-forms again, but only take the values part and
drop that into the "let" that I set up at compile time.

That's probably not the best way to solve the problem, but it is *a*
way, and may help you find a more correct solution.  ...and since I
don't really understand what you're trying to do, I had only limited
tests that I could try, so I've probably introduced some new bugs.
But at the very least, your original examples now work:

user=> (match '(1 2 3) (a b c) (list c b a))
(3 2 1)
user=> (let [z 4] (match '(1 2 3) (a b c) (list z c b a)))
(4 3 2 1)

--Chouser

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to