I've been working on a def-casemacro macro and I've run into some trouble.
The macro defines smaller macros based on a supplied name and test function.
Each one evaluates the first argument and then uses the test to compare the
result to each supplied case, evaluating whatever returns true or raising an
error otherwise. Your basic ecase like macros.

I've made macros like this in Common Lisp befor without any trouble but in
clojure the ` reader macro seems to namespace qualify everything inside of
it. This causes Clojure to freek out about all my variables and arguments.
So far the only solution I've found is to stick ~' infront of each variable
I use. But this is less then ideal cause you end up 2 or 3 backticks in with
stuff like ~~' infront of every local variable. Honetsly I'm not sure what
could be done about this, I just wanted to point it out in case it hasn't
been already.

Anyway I got it to work, so for those intrested, here it is:

(defn pair-seq [seq]
  (if seq
    (lazy-cons [(first seq) (second seq)]
           (pair-seq (rrest seq)))
    nil))


(defmacro def-casemacro [casename test]
 "Defines a macro named casename that uses test to compair the result of
form to each key/result pair"
  `(defmacro ~casename
     ~(format "Evaluates form and finds the first key/result pair that %s is
true for, evaluates it and returns the result. Error if none is found."
(print-str test))
     [~'form & ~'key-result-pairs]
     (let [~'key-gen (gensym "key__")
       ~'kr-pairs (pair-seq ~'key-result-pairs)]
       `(let [~~'key-gen ~~'form]
      (cond
       ~@(mapcat (fn [[~'key ~'result]]
               `((~'~test ~~'key-gen ~~'key) ~~'result)) ~'kr-pairs)
       true
       (throw (new Error (format ~(str "No " '~casename " for key: %s") (str
~~'key-gen)))))))))

;; Examples

(def-casemacro case =)
(def-casemacro instance?-case instance?)
(def-casemacro identical?-case identical?)
(def-casemacro isa?-case isa?)

;;Umm... Meta-Examples?
(comment
(case (first '(:foo :bar :biz))
             :bar
             5
             :foo
             7
             :biz
             6)
=> 7

(instance?-case "foo bar"
                   (if true
                     String
                     Double)
                   'yay!
                   Integer
                   'boo...)
=> yay!

(contains?-case #{:foo :bar :biz}
                   :foo
                   5
                   :bar
                   2
                   :biz
                   3)
=> 5

(isa?-case (class "foo")
                  FileInputStream
                  :file-stream
                  InputStream
                  :istream
                  String
                  :string)
=> :string
etc...
)

-- 
-Nate

--~--~---------~--~----~------------~-------~--~----~
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
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to