Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Regarding 2: The article punts on the question of how to implement such a system, because I think it's a hard question. I could have been clearer about that, and maybe in future I'll write an article speculating on some ways one could approach the problem. But I think it's an underappreciated problem, and I hope this article will spur other people to consider it.

Re 1:

In a.clj:

    (ns a (:refer-clojure))

    (defmulti if-match*
      (fn [pat _ _ _] (if (list? pat) (first pat) (type pat))))

    (defmacro if-match [pat expr then else]
      (if-match* pat expr then else))

    (defmethod if-match* clojure.lang.Symbol
      [pat expr then else]
      `(let [~pat ~expr] ~then))
In b.clj:

    (ns b (:refer-clojure) (:require a))

    ;; a 'foo pattern-macro that does negation
    (defmethod a/if-match* 'foo [pat expr then else]
      `(a/if-match ~(second pat) ~expr ~else ~then))
In c.clj:

    (ns c (:refer-clojure) (:require a))

    ;; a 'foo pattern-macro that is the identity pattern
    (defmethod a/if-match* 'foo [pat expr then else]
      `(a/if-match ~(second pat) ~expr ~then ~else))
Now, at the repl:

     user=> (use 'a)
     nil
     user=> (require 'b)
     nil
     user=> (if-match (foo x) 'yes x 'no)
     no
     user=> (require 'c)
     nil
     user=> (if-match (foo x) 'yes x 'no)
     yes
Note that 'require doesn't actually import the symbols defined by b.clj or c.clj, and despite that we're able to use the pattern-macro 'foo they define, because they're modifying if-match's dispatch-table. So our pattern-macros aren't being scoped the same way our regular macros are. I think this is wrong. Moreover, our pattern-macros have a single namespace, so we get collisions between what b.clj defines 'foo to mean and what c.clj defines it to mean, which is why (if-match (foo x) 'yes x 'no) changes behavior after the (require 'c).


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: