你会期望 Alternative
实例给你什么?我认为你可以通过观察另一个同时有这两个实例的类型来感受一下 Alternative
和 Semigroup
的区别,例如 Maybe String
:
λ > Just "a" <> Just "b"
Just "ab"
λ > Just "a" <> Nothing
Just "a"
λ > Nothing <> Just "b"
Just "b"
λ > Nothing <> Nothing
Nothing
λ > Just "a" <|> Just "b"
Just "a"
λ > Just "a" <|> Nothing
Just "a"
λ > Nothing <|> Just "b"
Just "b"
λ > Nothing <|> Nothing
Nothing
好的,主要区别似乎在于Just "a"
和Just "b"
。这是有道理的,因为在Semigroup
的情况下,您将它们合并在一起,而在Alternative
的情况下,则采取左偏的选项。
那么为什么不能为Either
创建一个Alternative
实例呢?如果您查看作为Alternative
类型类的一部分的函数:
λ > :i Alternative
class Applicative f => Alternative (f :: * -> *) where
empty :: f a
(<|>) :: f a -> f a -> f a
some :: f a -> f [a]
many :: f a -> f [a]
{-# MINIMAL empty, (<|>) #-}
它似乎定义了一个 empty
的概念;这是 (<|>)
运算符的恒等式。在这种情况下,恒等性质意味着恒等与其他内容之间的替代始终是另一个内容。
现在,你如何为 Either e a
构建一个恒等元素?如果你查看 Alternative
实例上的约束条件,你会发现它要求 f
具有一个 Applicative
实例。这很好,Either
声明了一个针对 Either e
的 Applicative
实例。正如你所看到的,Either
只是第二个类型变量(在 Either e a
中为 a
)的一个适用的函子。因此,Either e
的恒等元素需要 e
也有一个恒等元素。虽然可以构造一个类型,在该类型中 e
具有 Alternative
实例,但是无法为具有该 e
的 Either
创建 Alternative
实例,因为类型类定义中没有这样的约束(类似于:(Alternative e,Applicative (f e)) => Alternative (f e)
)。
TL;DR:如果我的话让你困惑了,我很抱歉。简单来说,对于 Either
,f
是错误的类型,Alternative
要求 f :: * -> *
,而 Either
的类型是 Either :: * -> * -> *
。
因此,Maybe
可以有 Alternative
实例,因为它的类型是 Maybe : * -> *
,并且具有 empty
所需的恒等元素(Nothing
)。查看Alternative
的所有实例,并注意每个实例数据类型的类型。
你可以使用 :k
在 ghci 中找到数据类型的类型:
λ > :k Maybe
Maybe :: * -> *
λ > :k Either
Either :: * -> * -> *