我一直在阅读"了解你的好事Haskell!"而现在我正在使用#34; The Functor Typeclass"部分。
在这里,他们通过修复第一种类型将Either变为仿函数,如下所示:
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
所以我想问一下,我怎样才能将Either变成第一种类型的仿函数(通过修复第二种类型),这样,我得到了fmap的以下定义
fmap f (Left x) = Left (f x)
fmap f (Right x) = Right x
答案 0 :(得分:7)
你不能; Either a
可以是一个仿函数,因为Either
的部分应用具有* -> *
种类,但您无法从右侧进行部分应用。
相反,您可能对Either
的{{3}}实例感兴趣:
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
对应fmap
的常规Either
; 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
还提供了second
函数,类似于元组的Bifunctor
实例:
> :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