为什么 Either 没有替代实例,而是有一个行为类似于替代的半群?

问题描述 投票:0回答:3

我是一个 Haskell 新手,我想知道为什么

Either
没有替代实例,而是一个半群,其行为正如我所期望的替代实例:

instance Semigroup (Either a b) where
Left _ <> b = b
a      <> _ = a

此实例丢弃或纠正“错误”,并且当两个操作数都标有

Right
时,它采用第一个。这不正是替代性提供的“选择”吗?

我希望半群实例大致如下:

instance (Semigroup b) => Semigroup (Either a b) where
Left e  <> _       = Left e
_       <> Left e  = Left e
Right x <> Right y = Right (x <> y)

这意味着它会传播错误并附加常规结果。

我想我对

Either
或所涉及的类型类有错误的概念。

haskell either alternative-functor semigroup
3个回答
18
投票

您希望

Alternative
实例能给您带来什么。我认为让您了解
Alternative
Semigroup
有何不同的一个好方法是查看另一种具有两者实例的类型:例如
Maybe String
:

λ > Just "a" <> Just "b"
Just "ab"
λ > Just "a" <> Nothing
Just "a"
λ > Nothing <> Just "b"
Just "b"
λ > Nothing <> Nothing
Nothing


λ > Just "a" <|> Just "b"
Just "a"
λ > Just "a" <|> Nothing
Just "a"
λ > Nothing <|> Just "b"
Just "b"
λ > Nothing <|> Nothing
Nothing

好吧,所以主要区别似乎是

Just "a"
Just "b"
。这是有道理的,因为您在
Semigroup
的情况下将它们组合起来,而不是在
Alternative
的情况下采用左偏选项。

现在为什么不能为

Alternative
提供
Either
实例。如果您查看属于
Alternative
类型类的函数:

λ > :i Alternative
class Applicative f => Alternative (f :: * -> *) where
  empty :: f a
  (<|>) :: f a -> f a -> f a
  some :: f a -> f [a]
  many :: f a -> f [a]
  {-# MINIMAL empty, (<|>) #-}

看起来它定义了一个

empty
的概念;这是
(<|>)
运算符的身份。案例中的身份意味着身份与其他事物之间的选择始终是其他事物。

现在,您将如何为

Either e a
构建身份?如果您查看
Alternative
实例上的约束,您会发现它需要
f
才能拥有
Applicative
实例。没关系,
Either
有一个为
Applicative
声明的
Either e
实例。正如您所看到的,
Either
只是第二个类型变量上的应用函子(在
a
的情况下为
Either e a
)。因此
Either e
的恒等式需要
e
也有一个恒等式。虽然可以构造一个类型,其中
e
具有
Alternative
的实例,但您无法使用该
Alternative
Either
制作
e
的实例,因为类型类定义中没有这样的约束(类似于:
(Alternative e, Applicative (f e)) => Alternative (f e)
)。

TL;DR:如果我的漫无目的失去了你,我很抱歉,缺点是

f
Either
的情况下是错误的种类
Alternative
需要
f :: * -> *
Either
属于种类
Either :: * -> * -> *

因此

Maybe
可以拥有
Alternative
的实例,因为它具有 kind
Maybe : * -> *
并且具有
Nothing
所需的身份概念 (
empty
)。查看
Alternative
的所有实例,并注意每个实例数据类型的类型。

您可以使用

:k
找到 ghci 中的数据类型:

λ > :k Maybe
Maybe :: * -> *
λ > :k Either
Either :: * -> * -> *

6
投票

根据上面发布的 ticket Dietrich Epp,

Alternative
的问题是
empty
。如果你有:

instance Alternative (Either a) where ...

您需要能够“凭空”提取一些价值

Either a b
,这是您的身份对象。一种可能的情况可能是:

instance (Monoid a)=> Alternative (Either a) where 
  empty = Left mempty
  ...

您还问为什么

Semigroup
实例是这样定义的,坦白说我也不明白。看来您提议的实例也将允许(兼容/合法)
Monoid
实例:

instance Monoid b=> Monoid (Either a b) where
  mempty = Right mempty

这与

Maybe
实例一致(Maybe 和 Either 之间的代数关系是显而易见的)。

所以情况不太好。部分问题是,如果你愿意的话,

Alternative
可以说是二等舱;它是一个单一的更高种类的东西,但它与
Monoid
Semigroup
的关系,显然并明确地(在文档中)形成了一个层次结构,尚未定义。

我确信图书馆邮件列表上已经进行了大量讨论,如果有一些明显的“正确”解决方案,那么转向它们可能会导致(在最坏的情况下无声的)破坏。


0
投票

虽然

Either
没有
Alternative
实例,但它确实有
Bialternative
实例。

{-# LANGUAGE QuantifiedConstraints #-}

class (Bifunctor p, forall a. Applicative (p a)) => Bialternative p where
  {-# MINIMAL left, ((<<|>>) | liftL2) #-}
  left :: a -> p a b

  (<<|>>) :: p (a -> b) c -> p a c -> p b c
  (<<|>>) = liftL2 id

  liftL2 :: (a -> b -> c) -> p a d -> p b d -> p c d
  liftL2 f a b = f `first` a <<|>> b

  (|>>) :: p a c -> p b c -> p b c
  a |>> b = liftL2 (const id) a b

  (<<|) :: p a c -> p b c -> p a c
  a <<| b = liftL2 const a b

这是

Bialternative
Either
实例。您可以使用
|>>
代替
<|>

instance Bialternative Either where
  left :: a -> Either a b
  left = Left

  (<<|>>) :: Either (a -> b) c -> Either a c -> Either b c
  Left f <<|>> Left a = Left (f a)
  Right c <<|>> _ = Right c
  _ <<|>> Right c = Right c

Bialternative
的实例应满足以下定律。

身份

left id <<|>> v = v

成分

left (.) <<|>> u <<|>> v <<|>> w = u <<|>> (v <<|>> w)

同态

left f <<|>> left x = left (f x)

交汇处

u <<|>> left y = left ($ y) <<|>> u

左抓

pure x <<|>> v = pure x

正确接球

left x <*> v = left x
© www.soinside.com 2019 - 2024. All rights reserved.