Thanks for the pointer, I haven't seen it and I'll be sure to give it a look when I have some time.
Matt On Thursday, November 8, 2012 11:29:12 AM UTC+1, Philip Potter wrote: > > Have you seen David Nolen's conj 2011 talk, "Predicate Dispatch"? It > covers exactly this material, but looks at trying to be somewhat more > efficient by not making method dispatch O(n) in the number of > implementations. At least as far as I understand it anyway. > > http://lanyrd.com/2011/clojure-conj/shhfg/ > > Phil > > On 7 November 2012 18:08, Matt Ridsdale <mrid...@gmail.com <javascript:>> > wrote: > > Hi, > > > > I was thinking about multimethods and the flexibility given by being > able to > > dispatch on the value of an arbitrary function of the arguments, > > instead of just the class of the first argument as in Java. It seems to > me > > that we could be even more flexible if each method implementation > > was associated with a predicate function of the args, instead of being > > associated with a fixed dispatch value. See the below code for an > example of > > what I mean: > > > > (ns polymorphism > > (:use clojure.test)) > > > > (def pm-to-dispatch-pred-map (ref {})) > > > > ; these are kind of like multimethods, so let's give them a similar name > - > > polymethods. > > (defmacro defpoly [a-name [& args]] > > "define a polymethod signature" > > `(do > > (defn ~a-name [~@args] > > (let [dispatch-pred-to-impl-fn-map# (get > > @polymorphism/pm-to-dispatch-pred-map ~a-name) > > matching-keys# (filter #(apply % [~@args]) (keys > > dispatch-pred-to-impl-fn-map#)) > > num-matches# (count matching-keys#)] > > (case num-matches# > > 0 (throw (Exception. (str "No matching function defined for > > polymethod " ~a-name " and args " [~@args]))) > > 1 (apply (get dispatch-pred-to-impl-fn-map# (first > > matching-keys#)) [~@args]) > > (throw (Exception. (str num-matches# " matching functions > > defined for polymethod " ~a-name " and args " [~@args])))))) > > (dosync (alter polymorphism/pm-to-dispatch-pred-map assoc ~a-name > > {})))) > > > > (defmacro defpolyimpl [a-name dispatch-pred & body] > > "define a polymethod implementation, for a given dispatch predicate" > > `(let [dispatch-pred-to-impl-fn-map# (get > > @polymorphism/pm-to-dispatch-pred-map ~a-name)] > > (if (nil? dispatch-pred-to-impl-fn-map#) > > (throw (Exception. "No such polymethod: " ~a-name))) > > (let [impl-fn# (fn ~@body)] > > (dosync (alter polymorphism/pm-to-dispatch-pred-map assoc ~a-name > > (assoc dispatch-pred-to-impl-fn-map# ~dispatch-pred impl-fn#))) > > ~a-name))) > > > > > > (deftest polymorphism-test > > (defpoly find-name [a-map]) > > > > (defpolyimpl find-name > > #(and (contains? % :first-name) (contains? % :surname)) > > [a-map] > > (str (:first-name a-map) " " (:surname a-map))) > > > > (defpolyimpl find-name > > #(contains? % :full-name) > > [a-map] > > (:full-name a-map)) > > > > (def personA {:first-name "John" :surname "Smith"}) > > (def personB {:full-name "Jane Bloggs"}) > > (is (= "John Smith" (find-name personA))) > > (is (= "Jane Bloggs" (find-name personB)))) > > > > (run-tests) > > > > I think this system of "dispatch predicates" instead of dispatch values > is > > more flexible/expressive, because you can easily emulate multimethods: > if > > your multimethod had dispatch function dispatch-fn and a dispatch value > > dispatch-val, you would use > > #(isa? (apply dispatch-fn %&) dispatch-val) > > as the dispatch predicate. Whereas I can't see a simple way to express > an > > arbitrary set of "polymethods" in terms of multimethods. > > > > There are a few problems I can see with this approach, but none of them > seem > > to be dealbreakers to me: > > - You need to filter a list to determine the appropriate function > > implementation, whereas multimethods just look up the dispatch value in > a > > hash map. This could decrease performance if there are many > implementations. > > - In this version, they don't compose well: somebody could define a new > > implementation somewhere else which breaks your code, because two > dispatch > > predicates match the args you're using. We could get around this with > > something like prefer-method, or by remembering the order in which > > implementations are defined, and always taking the first/last one which > > matches the args. > > - Maybe this shouldn't be called polymorphism, since there is no notion > of > > type involved anywhere, except for the "types" defined by the > predicates. > > > > Is there anything wrong with this approach, or any particular reason it > > wasn't done this way in Clojure? > > > > -- > > You received this message because you are subscribed to the Google > > Groups "Clojure" group. > > To post to this group, send email to clo...@googlegroups.com<javascript:> > > Note that posts from new members are moderated - please be patient with > your > > first post. > > To unsubscribe from this group, send email to > > clojure+u...@googlegroups.com <javascript:> > > 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 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