我将首先介绍一个具体的问题(StackOverflow 的人就是这样)。
假设您定义了一个简单类型
data T a = T a
这种类型是一个Functor
, Applicative
and a Monad
。忽略自动派生,要获取这些实例,您必须编写每个实例,即使Monad
暗示Applicative
,这意味着Functor
。
更重要的是,我可以定义一个这样的类
class Wrapper f where
wrap :: a -> f a
unwrap :: f a -> a
这是一个相当强的条件,它绝对意味着Monad
,但我写不出来
instance Wrapper f => Monad f where
return = wrap
fa >>= f = f $ unwrap fa
因为出于某种原因,这意味着“一切都是Monad
(every f
),仅当它是Wrapper
”,而不是“一切都是Wrapper
is a Monad
".
同样,你不能定义Monad a => Applicative a
and Applicative a => Functor a
实例。
您不能做的另一件事(这可能只是相关的,我真的不知道)是让一个类成为另一个类的超类,并提供子类的默认实现。当然,这很棒class Applicative a => Monad a
,但是我仍然需要定义Applicative
在我可以定义之前实例Monad
one.
这不是咆哮。我写了很多,因为否则很快就会被标记为“太宽泛”或“不清楚”。问题归结为标题。
我知道(至少我很确定)这有一些理论上的原因,所以我想知道这里到底有什么好处。
作为一个子问题,我想问是否有可行的替代方案仍然保留所有(或大部分)这些优点,但允许我写的内容。
添加:
我怀疑答案之一可能是“如果我的类型是Wrapper
,但我不想使用Monad
这意味着什么?”。对此我问,为什么编译器不能选择最具体的一个?如果有一个instance Monad MyType
,肯定比instance Wrapper a => Monad a
.