我一直在阅读这本很棒的好书,但我在 Applicative Functors 上有些挣扎。
在下面的示例max中应用了两个 Maybe 函子的内容并返回Just 6。
max <$> Just 3 <*> Just 6
为什么在以下示例中Left "Hello"返回而不是 Either 仿函数的内容:Left "Hello World"?
(++) <$> Left "Hello" <*> Left " World"
我一直在阅读这本很棒的好书,但我在 Applicative Functors 上有些挣扎。
在下面的示例max中应用了两个 Maybe 函子的内容并返回Just 6。
max <$> Just 3 <*> Just 6
为什么在以下示例中Left "Hello"返回而不是 Either 仿函数的内容:Left "Hello World"?
(++) <$> Left "Hello" <*> Left " World"
这是因为Functor实例(Applicative等)中的类型参数是第二个类型参数。在
Either a b
a类型和Left值不受函数或应用操作的影响,因为它们被视为失败案例或无法访问。
instance Functor (Either a) where
fmap _ (Left x) = Left x
fmap f (Right y) = Right (f y)
使用Right,
(++) <$> Right "Hello" <*> Right " World"
获得连接。
为了补充丹尼尔的出色回答,我想提出几点:
首先,这是 Applicative 实例:
instance Applicative (Either e) where
pure = Right
Left e <*> _ = Left e
Right f <*> r = fmap f r
你可以看到这是“短路”——只要它碰到 a Left,它就会中止并返回那个 Left。您可以通过穷人的严格分析来检查这一点:
ghci> (++) <$> Left "Hello" <*> undefined
Left "Hello" -- <<== it's not undefined :) !!
ghci> (++) <$> Right "Hello" <*> undefined
*** Exception: Prelude.undefined -- <<== undefined ... :(
ghci> Left "oops" <*> undefined <*> undefined
Left "oops" -- <<== :)
ghci> Right (++) <*> undefined <*> undefined
*** Exception: Prelude.undefined -- <<== :(
其次,你的例子有点棘手。一般来说,函数的类型和einEither e是不相关的。这是<*>s 类型:
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
如果我们进行替换f-->> Either e,我们得到:
(<*>) :: Either e (a -> b) -> Either e a -> Either e b
尽管在您的示例e和a匹配中,通常它们不会,这意味着您不能多态地实现Either e将函数应用于左侧参数的 Applicative 实例。