是否有可能在arity上重载Clojure多方法?

And*_*use 18 clojure multimethod

我有一些代码使用多方法,理想情况下会重载函数(在这种情况下,多功能),以便我可以传递更高阶的函数来帮助测试,例如.

这是一个例子:

(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))))
Run Code Online (Sandbox Code Playgroud)

所以我的defn提供了arity重载,但我想知道defmethod是否支持这样的事情.(我想你不想为每个defmethod声明做这件事.)

这是最合适的(我敢说,惯用)方法,还是有更好的方法?

kot*_*rak 14

这很好.存在库的"用户"界面和"类型"界面.它们可能是相同的,但它们不必相同.

在您的情况下,"用户"界面which-colour."类型"接口是which-colour-mm(确定,不是真的,但仅仅是为了参数).您的图书馆用户无需了解多方法.

另一方面,提供新颜色的人 - 比如说:purple- 并不需要关心多个样板.这是为他处理的which-colour.

这是一个完全有效的设计!

但当然有一个价格标签:假设你有一种颜色,它有更多的执行方式......现在,你被锁定在一个可能更慢的界面.

为了澄清这一点:假设你有一个集合界面.您提供了一个函数 - conj- 允许用户向集合中添加元素.它实现如下:

(defn conj
  [coll & elements]
  (reduce conj1 coll elements))
Run Code Online (Sandbox Code Playgroud)

conj1是"类型"接口(例如,多方法或协议函数):它向集合添加一个元素.因此,提供新集合类型的人只需实现添加单个参数的简单情况.并且自动地,新类型还将支持添加多个元素.

但是现在假设你有一个集合类型,它允许更快的方式来添加几个元素而不是一个接一个地添加.此功能现在无法使用.

因此,您将多方法/协议功能作为功能conj本身.现在集合可以使用更快的方式.但每个实现必须提供多元素样板.

这是一个权衡取决于您的决定.没有正确的方式(tm).两者都可以被认为是惯用的.(虽然我个人会尝试尽可能多地使用第一个.)

因人而异.

编辑:在调度值中没有编码的多个arity方法的示例.

(defmulti which-colour-mm (fn [m & args] (:colour m)))
(defmethod which-colour-mm :blue
  ([m] (print m))
  ([m f] (f m)))
Run Code Online (Sandbox Code Playgroud)