如何将协议功能与同名和不同功能的功能结合起来?

时间:2015-09-08 17:13:12

标签: clojure

我有一个函数foo,它接受​​一个参数,其实现取决于参数的类型,因此是一个协议:

(defprotocol Foo
  (foo [x]))

在同一名称空间中,我还想要一个具有相同名称(foo)的函数,该函数接受变量参数,并且每个参数都调用单参数foo。类似的东西:

(defn foo [x1 x2 & more]
  (doseq [x (concat [x1 x2] more)])
    (foo x))))

如何实现?

2 个答案:

答案 0 :(得分:2)

使用defprotocol您已声明函数foo。稍后调用(defn foo ...)会有效地覆盖您之前的声明。

一个常见的习惯用法是在你的协议fn(即-)前加-foo。这基本上是匈牙利语符号“这是一个内部协议函数。在这个命名空间中有一个包装器。你应该调用它。”这使协议保持打开以进行扩展,但允许您包装调用。

我要考虑的另一件事是名称foo是否适合您的包装器。它在多个Foo上运行的事实表明,do-foos之类的东西更合适。

答案 1 :(得分:2)

只需添加Tim Pote的答案,我就引用answer from Stuart Halloway

  协议是实施者的合同,而不是呼叫者的合同。如果您更改了实施者的合同,那么实施者必须更改。

     

[...]具有任何对象的合理默认值的函数。通常,这样的功能根本不需要成为实施者(即协议)合同的一部分。

协议实现者正在解放,因为你可以在公共api fn中设置默认值或为多个arities添加支持(如你的情况),而不必担心具体实现中的所有这些。