在为Collection / Container类型编写类时(如果我重新发明轮子,请指向现有类型),以提供一个通用界面来添加和删除任何' Collection'类型。
class (Eq (c a), Monoid (c a)) => Collection c a where
emptyColl :: c a -> Bool
splitColl :: c a -> (a, c a)
toColl :: a -> c a
size :: c a -> Int
combineColl :: a -> c a -> c a
(>|<) :: a -> c a -> c a
a >|< c = combineColl a c
我注意到Collection的实例也可以是Foldable的实例。使用splitColl和emptyColl。所以你也不需要写一个Foldable,如果你在几个类上做了这样的构造,那么可以节省大量的时间,写出琐碎的实例。
我试图让Collection成为Foldable的一个实例。然而,类似乎不能从其他类实例化它们吗? 我收到以下错误消息:
instance Functor (Collection c) where
The first argument of ‘Functor’ should have kind ‘* -> *’,
but ‘Collection c’ has kind ‘* -> GHC.Prim.Constraint’
In the instance declaration for ‘Functor (Collection c)’
instance Functor (Collection c a) where
The first argument of ‘Functor’ should have kind ‘* -> *’,
but ‘Collection c a’ has kind ‘GHC.Prim.Constraint’
In the instance declaration for ‘Functor (Collection c a)’
我怎样才能获得所需的功能?我认为模板Haskell可能是去这里的方式,我从来没有用过它,一个例子会很棒:)
提前致谢!
PS:我一直在写haskell大约一年,想到的小小提示非常感谢答案 0 :(得分:2)
这方面的标准技巧是提供适当功能的实现,并让用户编写自己的实例。例如,您可以编写
fmapColl :: (Collection c a, Collection c b) => (a -> b) -> c a -> c b
fmapColl f ca
| emptyColl ca = mkEmptyColl -- you don't have this in your class, but probably should
| otherwise = case splitColl ca of
(a, ca') -> f a >|< fmapColl f ca'
假设我们有一个合适的类型类,比如CFunctor
:
class CFunctor f where
type ConstraintI f
type ConstraintO f
cfmap :: (ConstraintI i, ConstraintO o) => (i -> o) -> f i -> f o
然后对于Collection
之类的给定Set
个实例,我们可以使用最少的实际代码来实例化CFunctor
:
instance CFunctor Set where
type ConstraintI Set = Ord
type ConstraintO Set = Ord
cfmap = fmapColl
您可以看到此模式 - 为用户定义一个“默认”实现,例如在base library's fmapDefault
中放入他们的实例。