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

Reply via email to