我一直在读"Learn You A Haskell for Great Good!",现在我在"The Functor Typeclass"部分。
在这里,他们通过修复第一种类型将 Or 变成函子,如下所示:
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
所以我想问,我怎样才能将 要么 变成第一种类型的函子(通过修复第二种类型(,这样,我得到了以下 fmap 的定义
fmap f (Left x) = Left (f x)
fmap f (Right x) = Right x
你不能;Either a
可以是函子,因为Either
的部分应用具有某种* -> *
,但你不能从右边做部分应用。
相反,您可能对Either
的Bifunctor
实例感兴趣:
instance Bifunctor Either where
bimap f _ (Left a) = Left (f a)
bimap _ g (Right b) = Right (g b)
bimap
采用两个函数,一个用于Either
包装的两种类型中的每一种。
> bimap (+1) length (Left 3)
Left 4
> bimap (+1) length (Right "hi")
Right 2
还有一些专注于一种或另一种类型的first
和second
函数。second
对应于Either
的常规fmap
;first
是您正在寻找的功能。
> first (+1) (Left 3)
Left 4
> first (+1) (Right 3)
Right 3
> second (+1) (Left 3)
Left 3
> second (+1) (Right 3)
Right 4
(帽子提示到@leftaroundabout(
Control.Arrow
模块提供了left
函数,它实际上与second
相同,但具有更具描述性的名称和不同的派生。比较它们的类型:
> :t Data.Bifunctor.second
Data.Bifunctor.second :: Bifunctor p => (b -> c) -> p a b -> p a c
> :t Control.Arrow.left
Control.Arrow.left :: ArrowChoice a => a b c -> a (Either b d) (Either c d)
second
是硬编码的,可以与函数一起使用,并且可以通过p ~ Either
进行限制。left
是硬编码的,可以与Either
一起使用,并且可以通过a ~ (->)
进行限制。
令人困惑的是,Control.Arrow
还提供了类似于元组Bifunctor
实例的second
函数:
> :t Control.Arrow.second
Control.Arrow.second :: Arrow a => a b c -> a (d, b) (d, c)
> Control.Arrow.second (+1) (1,2) == Data.Bifunctor.second (+1) (1,2)
True