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

kis*_*aya 4 haskell functor either

我一直在读"为了好大学而学习你的哈斯克尔!" 而现在我正在使用"The Functor Typeclass"部分.

在这里,他们通过修复第一种类型将Either变为仿函数,如下所示:

instance Functor (Either a) where
  fmap f (Right x) = Right (f x)
  fmap f (Left x)  = Left x
Run Code Online (Sandbox Code Playgroud)

所以我想问一下,我怎样才能将Either变成第一种类型的仿函数(通过修复第二种类型),这样,我得到了fmap的以下定义

fmap f (Left x) = Left (f x)
fmap f (Right x)  = Right x
Run Code Online (Sandbox Code Playgroud)

che*_*ner 7

你不能; Either a可以是一个仿函数因为部分应用Either有种* -> *,但你不能从右边做部分应用.

相反,您可能对以下Bifunctor实例感兴趣Either:

instance Bifunctor Either where
    bimap f _ (Left a) = Left (f a)
    bimap _ g (Right b) = Right (g b)
Run Code Online (Sandbox Code Playgroud)

bimap采用两个函数,一个用于包装的两种类型中的每一种Either.

> bimap (+1) length (Left 3)
Left 4
> bimap (+1) length (Right "hi")
Right 2
Run Code Online (Sandbox Code Playgroud)

也有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
Run Code Online (Sandbox Code Playgroud)

(帽子提示@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)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)