(...)根据 Typeclassopedia 文章,给定类型必须是 Applicative 才能成为 Monad (或者理论上应该如此)。
是的,您的括号旁正是这里的问题。理论上, any也Monad
应该是Applicative
,但这实际上不是必需的,因为历史原因(即,因为Monad
已经存在了更长的时间)。这也不是 的唯一特点Monad
。
考虑相关类型类的实际定义,取自base
Hackage 上的包源。
这是Applicative
:
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
(*>) :: f a -> f b -> f b
(<*) :: f a -> f b -> f a
...我们可以观察到以下几点:
- 给定当前存在的类型类,上下文是正确的,即它需要
Functor
.
- 它是根据函数应用定义的,而不是(从数学角度可能更自然)提升元组的术语。
- 它包括技术上多余的运算符,相当于提升常量函数。
同时,这里是Monad
:
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
...我们可以观察到以下几点:
- 上下文不仅忽略
Applicative
,而且忽略 ,Functor
这两者在逻辑上都被隐含Monad
但未明确要求。
- 它也是根据函数应用定义的,而不是使用
return
and的更自然的数学定义join
。
- 它包括一个技术上多余的运算符,相当于提升一个常量函数。
- 它还包括
fail
根本不适合的内容。
一般来说,Monad
类型类与其所基于的数学概念的不同之处可以追溯到其作为编程抽象的历史。有些,比如它所共有的函数应用偏见Applicative
,是函数式语言中存在的反映;其他人,喜欢fail
或缺乏适当的阶级背景,是历史上的偶然事件。
这一切都归结为拥有一个 的实例Monad
意味着一个 的实例Applicative
,这反过来又意味着一个 的实例Functor
。类上下文只是明确地形式化了这一点;无论如何,它仍然是正确的。就目前而言,给定一个Monad
实例,两者Functor
和Applicative
都可以以完全通用的方式定义。与更通用的完全相同的意义上Applicative
“没有那么强大” :如果您复制+粘贴通用实例,则 Any是自动的,但是存在不能定义为的实例。Monad
Monad
Applicative
Applicative
Monad
一个类上下文,就像Functor f => Applicative f
说两件事:后者暗示前者,并且必须存在一个定义来实现该暗示。在许多情况下,无论如何定义后者都会隐式定义前者,但编译器通常无法推断出这一点,因此需要显式写出这两个实例。可以用Eq
and观察到同样的事情Ord
——后者显然暗示了前者,但您仍然需要定义一个Eq
实例才能为Ord
.