【发布时间】:2017-11-28 23:32:46
【问题描述】:
我经常开始考虑要定义的类型类的问题,并意识到当我开始编码时,我不需要类型类而是可以用代数数据类型来解决我的问题,这似乎更简单。因此,我想知道什么时候需要类型类。
据我了解,类型类是一种表示特定类型存在特定函数的方式。例如,当类型 MyType 是 Monoid 的一个实例时,我可以使用函数mempty :: MyType 和mappend :: MyType -> MyType -> MyType,这样幺半群法则成立。
我们可以通过将 Monoid 定义为类型而不是类型类来实现代数数据类型:
data Monoid a = Monoid { mempty :: a
, mappend :: a -> a -> a}
然后通过定义Monoid MyType 类型的新值(通过将其声明为实例来完成类型类)来说类型 MyType 是一个幺半群:
monoidMyType :: Monoid MyType
monoidMyType = Monoid { mempty = ...
, mappend = \a b -> ... }
然后,我们可以编写对幺半群进行操作的函数,例如:
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 时,必须显式传递幺半群值。虽然不必明确通过它更实际一点,但在我看来这不是一个主要障碍。
事实上,我看到了代数数据类型相对于类型类的一个优势:您可以将不同函数中的类型关联起来:
data Bla a b = Bla {f1 :: a -> b, f2 :: b -> a, ...}
使用类型类执行此操作(我相信)需要使用多参数类型类扩展。
是否有理由使用我在这里没有看到的类型类?
在设计软件时,您是否可以交替选择使用类型类或代数数据类型,或者在某些情况下您不能没有类型类?
【问题讨论】:
-
类型类和 ADT 是非常正交的概念。
标签: haskell