2012-12-14 16 views
1

如何为单个数据类型创建多方法的多个实现?是否可以为同一类型提供多种不同的多方法实现?

这可能不是一个很好的例子,但我希望它描述了一个思路:能治疗嵌套向量既是序列:

repl> (def thing [[[1] []] [27] [18 [32 35]]]) 

repl> (fmap count thing) 
[2 1 2] 

和树木:

repl> (fmap (partial + 1) thing) 
[[[2] []] [28] [19 [33 36]]] 

是什么为相同类型创建和使用多个multimethod实现的一般方法?

+0

我不认为单独使用multimethods会有很大的帮助 - “defmethod”会替换之前为该分派值定义的任何方法。 – Alex

+0

如果函数做了两件完全不同的事情,为什么不声明两个不同的函数/多方法呢? – DaoWen

+0

多方法在任何事物上都是多态的,而不仅仅是类型上(尽管这是最常见的)。所以,如果你有某种方法来区分你想要用一种方法处理的相同类型的实体和你想处理另一种类型的实体,那么这很好。 –

回答

0

multimethods的想法是,你对“不同的参数”(而不一定是不同的类型)做“相同的操作”。如果你想对“相同的参数”做一个“不同的操作”,那么多方法将不适合,就像@DaoWen所建议的那样,仅仅使用单独的函数(或者甚至单独的多方法)可能是正确的方法去做吧。

如果您有某种编程方式区分参数的方式,并且基于这些区分特征使用不同的方法实现方式具有概念意义,那么您可以使用defmultidispatch-fn参数进行区分。

作为一个简单的例子,您可以使用一个key:foo作为dispatch-fn,它将在映射中与key:foo关联的值进行分派,该映射作为单个参数传递给您的多方法。

+0

感谢您的回答!但是,我不能只用一个不同的操作 - 这会挫败Functor抽象的整个点!我会试一试'dispatch-fn',看看它是如何工作的。感谢您的建议! –

1

在你的问题中,你需要调用函数类型(fmap first arg)参数。 AFAIK没有(简单的)方法来检测任何函数的参数类型(纠正我,如果它是错误的)。所以你必须添加这个作为一些元数据参数或类似的东西。例如

(defmulti fmap (fn [f _] ((comp :arg-seq? meta) f))) 

(defmethod fmap true [f col] 
    (map-tree f col)) 

(defmethod fmap false [f col] 
    (map f col)) 

(fmap (with-meta inc {:arg-seq? true}) thing) 
-> [[[2] []] [28] [19 [33 36]]] 

(fmap (with-meta count {:arg-seq? false}) thing) 
-> (2 1 2) 

但这看起来不太好。如果有其他方法可以得到函数参数类型,那么解决方案可以更好看。

+0

有趣的建议,谢谢。 –

相关问题