如何使Either成为第二种类型的仿函数

时间:2018-05-09 12:34:28

标签: haskell functor either

我一直在阅读"了解你的好事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

1 个答案:

答案 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

还有firstsecond函数专注于一种或另一种类型。 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