我经常开始考虑要定义的类型类的问题,并且当我开始编码时意识到我不需要类型类并且可以用代数数据类型来解决我的问题,这似乎更直截了当。因此,我想知道何时需要类型类。
据我所知,类型类是一种说某些类型存在某些函数的方法。例如,当MyType类型是Monoid的一个实例时,我可以使用函数mempty :: MyType
和mappend :: MyType -> MyType -> MyType
,这样就可以保持幺半群定律。
通过将Monoid定义为类型而不是类型类,我们可以对代数数据类型实现相同的效果:
data Monoid a = Monoid { mempty :: a
, mappend :: a -> a -> a}
然后通过定义类型为Monoid MyType
的新值(类型类通过声明为实例来完成)来说类型MyType是monoid:
monoidMyType :: Monoid MyType
monoidMyType = Monoid { mempty = ...
, mappend = \a b -> ... }
然后,我们可以编写像monoids一样运行的函数:
dummyFun :: Monoid a -> a -> a
dummyFun m x = mempty m x
通过显式传递适当的" monoid值":
来使用这些函数result = dummyFun monoidMyType valueOfMyType
与类型类相同的最后两个步骤将非常相似:
dummyFun :: (Monoid a) => a -> a
dummyFun x = mempty x
result = dummyFun valueOfMyType
我看到的唯一重要区别是,对于代数数据类型,当我们调用函数dummyFun
时,必须明确地传递monoid值。虽然不必明确地传递它更实际,但它并不像我看来是一个主要障碍。
事实上,我发现代数数据类型具有优于类型类的优势:您可以将不同函数的类型联系在一起:
data Bla a b = Bla {f1 :: a -> b, f2 :: b -> a, ...}
使用类型类来执行此操作(我相信)需要使用多参数类型类扩展。
是否有理由使用我在这里看不到的类型类?
在设计软件时,您是否可以互换选择使用类型类或代数数据类型,还是在没有类型类的情况下?