Is it possible to overload Clojure multi-methods on arity?

前端 未结 3 835
借酒劲吻你
借酒劲吻你 2021-02-12 13:35

I have some code that uses multi-methods and would ideally like to overload the function (in this case, multi-function) so that I can pass in a higher order function to help wit

3条回答
  •  逝去的感伤
    2021-02-12 13:57

    This is perfectly fine. There is the "user" interface and the "type" interface of a library. They may be identical, but they don't have to.

    The "user" interface is in your case which-colour. The "type" interface is which-colour-mm (ok, not really, but just for the sake of the argument). The user of your library does not need to know about the multimethod.

    On the other hand someone providing a new colour - say :purple - does not have to care about multi-arity boilerplate. This is handled for him in which-colour.

    This is a perfectly valid design!

    But of course there's a price tag: Suppose you have a colour, which has some more perfomant way to do things... Now, you are locked into a possible slower interface.

    To clarify this a little: Suppose you have a collection interface. You provide a function - conj - which allows the user to add elements to the collection. It is implemented like this:

    (defn conj
      [coll & elements]
      (reduce conj1 coll elements))
    

    conj1 is the "type" interface (eg. a multimethod or protocol function): it adds one element to the collection. So someone supplying a new collection type has only to implement the simple case of adding a single argument. And automagically the new type will also support adding multiple elements.

    But now suppose you have a collection type, which allows a faster way to add several elements than just adding one after the other. This capability cannot be used now.

    So you make the multimethod/protocol function the function conj itself. Now the collection can use the faster way. But each implementation must provide the multiple elements boilerplate.

    This is a trade-off and up to your decision. There is not Right Way(tm). Both can be considered idiomatic. (Although I personally would try to go with the first one as often as possible.)

    YMMV.

    Edit: An example of multi arity methods without coding in the dispatch value.

    (defmulti which-colour-mm (fn [m & args] (:colour m)))
    (defmethod which-colour-mm :blue
      ([m] (print m))
      ([m f] (f m)))
    

提交回复
热议问题