starting clojure multimethod

starting - ¿Es posible sobrecargar los métodos múltiples de Clojure en arity?



clojure install (3)

Básicamente, puedes enviar cualquier cosa, ni el tipo ni el número de argumentos tienen que ser consistentes ... como esto:

(defn- map-classes [an-object] (let [cmap {1 :thing 2 666 3 "yada"} the-class (class an-object)] (get cmap an-object the-class))) (defn- mk-class [& args] (map #(map-classes %) args)) (defmulti play-thing mk-class ) (defmethod play-thing [:thing] [v] (= 1 v)) (defmethod play-thing [666] [v] (= 2 v)) (defmethod play-thing ["yada" String] [v x] (str x v))

Las posibilidades son infinitas

Tengo algún código que utiliza métodos múltiples y, idealmente, me gustaría sobrecargar la función (en este caso, funciones múltiples) para poder pasar una función de orden superior para ayudar con las pruebas, por ejemplo.

Aquí está el ejemplo:

(ns multi) (defn my-print [m] (println "The colour is" (:colour m))) (defmulti which-colour-mm (fn [m f] (:colour m))) (defmethod which-colour-mm :blue [m f] (f m)) (defmethod which-colour-mm :red [m f] (f m)) (defmethod which-colour-mm :default [m f] (println "Default: Neither Blue nor Red")) (defn which-colour ([m] (which-colour-mm m my-print)) ([m f] (which-colour-mm m f))) (which-colour {:colour :blue :object :ball}) (which-colour {:colour :yellow :object :ball}) (which-colour {:colour :blue :animal :parrot} (fn [m] (println "The " (:animal m) "is" (:colour m))))

Así que mi definición proporciona la sobrecarga de aridad pero me pregunto si defmethod soporta algo como esto. (Supongo que no querría hacerlo para cada declaración de método).

¿Es este el enfoque más adecuado (me atrevo a decir, idiomático ) o hay una mejor manera?


Esto está perfectamente bien. Existe la interfaz de "usuario" y la interfaz de "tipo" de una biblioteca. Pueden ser idénticos, pero no tienen que hacerlo.

La interfaz de "usuario" es, en su caso, de which-colour . La interfaz de "tipo" es which-colour-mm (bueno, no realmente, pero solo por el bien del argumento). El usuario de su biblioteca no necesita conocer el método múltiple.

Por otro lado, alguien que proporcione un nuevo color, por ejemplo :purple , no tiene que preocuparse por la caldera de múltiples aridades. Esto se maneja para él en which-colour .

¡Este es un diseño perfectamente válido!

Pero, por supuesto, hay una etiqueta de precio: suponga que tiene un color, que tiene una forma más eficaz de hacer las cosas ... Ahora, está bloqueado en una posible interfaz más lenta.

Para aclarar esto un poco: suponga que tiene una interfaz de colección. Proporciona una función ( conj ) que le permite al usuario agregar elementos a la colección. Se implementa así:

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

conj1 es la interfaz de "tipo" (p. ej., una función de protocolo o conj1 ): agrega un elemento a la colección. Entonces, alguien que proporciona un nuevo tipo de colección solo tiene que implementar el caso simple de agregar un solo argumento. Y, automáticamente, el nuevo tipo también admitirá la adición de múltiples elementos.

Pero ahora suponga que tiene un tipo de colección, que permite una manera más rápida de agregar varios elementos que solo agregar uno después del otro. Esta capacidad no se puede utilizar ahora.

Así que haces que la función multimethod / protocol sea la función conj sí misma. Ahora la colección puede usar la forma más rápida. Pero cada implementación debe proporcionar los elementos múltiples repetitivos.

Esta es una compensación y depende de su decisión. No hay camino correcto (tm). Ambos pueden considerarse idiomáticos. (Aunque personalmente intentaría ir con el primero tan a menudo como sea posible).

YMMV.

Edición: un ejemplo de métodos de múltiples aridades sin codificación en el valor de envío.

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


Puede hacerlo utilizando métodos múltiples como se muestra a continuación:

(defmulti which-colour-mm (fn [m & args] [(count args) (:colour m)])) (defmethod which-colour-mm [0 :blue] [m] (print m)) (defmethod which-colour-mm [1 :blue] [m f] (f m)) user=> (which-colour-mm {:colour :blue :object :ball}) {:colour :blue, :object :ball}nil user=> (which-colour-mm {:colour :blue :object :ball} print) {:colour :blue, :object :ball}nil