我知道现在很难在不破坏现有代码的情况下进行更改,但我想知道为什么首先要这样做。
为什么不只是:
sealed trait Either[+A, +B]
case class Left[A](x: A) extends Either[A, Nothing]
case class Right[B](x: B) extends Either[Nothing, B]
Run Code Online (Sandbox Code Playgroud)
这里是否有一些我没有看到的缺点......?
lef*_*out 11
不确定这个答案与 Scala 到底有多相关,但它肯定是在 Haskell 中,这显然是 Scala 的Either借用处,所以这可能是 Scala 这样做的最佳历史原因。
Either是规范的副产品,即对于任何类型A,B你有
EitherA,B ? A ? BLeftA,B : A -> A?BRightA,B : B -> A?BY和任何函数and ,都只存在一个具有and属性的函数。fA : A -> YfB : B -> Yf : A?B -> YfA = f ? LeftA,BfB = f ? RightA,B为了以数学方式表达这一点,Left明确您正在使用的特定信息是非常有帮助的,因为否则态射的域将全部不清楚。在 Scala 中,由于隐式协变转换,这可能是不必要的,但在数学和 Haskell 中不是。
在 Haskell 中,这根本不是问题,因为类型推断会自动执行所需的操作:
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /tmp/haskell-stack-ghci/2a3bbd58/ghci-script
Prelude> let right2 = Right 2
Prelude> let left42 = Left 42.0
Prelude> (+) <$> right2 <*> left42
Left 42.0
Run Code Online (Sandbox Code Playgroud)
显然,在 Scala 中,Haskell 只是将未指定的第二个参数left42作为类型变量保留(除非启用了单态限制),因此您以后可以在任何需要 some Either Double Rfor any type 的上下文中使用它R。当然也可以明确表示
right2 :: Either a Int
right2 = Right 2
left42 :: Either Double a
left42 = Left 42
main :: IO ()
main = print $ (+) <$> right2 <*> left42
Run Code Online (Sandbox Code Playgroud)
这在 Scala 中当然也是可能的。
Rex*_*err 10
我发现您的计划没有任何有意义的缺点。在过去八年左右的时间里,我使用了我自己的变体,Either这与您在另一个名称下描述的完全一样(Ok[+Y, +N]带有Yes[+Y]和No[+N]作为替代)。(历史记录:我开始时Either没有偏右,并且想要一些偏右的东西;但后来我继续使用我的版本,因为只有一半的类型更方便。)
我发现唯一重要的情况是当您模式匹配一个分支并且不再访问另一个分支的类型信息时。
def foo[A, B: Typeclass](e: Either[A, B]) =
implicitly[Typeclass[B]].whatever()
// This works
myEither match {
case l: Left[L, R] => foo(l)
case r: Right[L, R] => foo(r)
}
Run Code Online (Sandbox Code Playgroud)
def bar[N, Y: Typeclass](o: Ok[N, Y]) =
implicitly[Typeclass[Y]].whatever()
// This doesn't work
myOk match {
case y: Yes[Y] => bar(y) // This is fine
case n: No[N] => bar(n) // Y == Nothing!
}
Run Code Online (Sandbox Code Playgroud)
但是,我从不这样做。我可以o用来获得正确的类型。所以没关系!其他一切都更容易(例如模式匹配和更改一种情况而不是另一种情况……除了切换无人居住的分支的类型之外,您不需要无缘无故地case Left(l) => Left(l)重建它Left)。
还有其他情况(例如提前设置类型)看起来应该很重要,但实际上几乎不可能解决(例如,因为协方差无论如何都会找到共同的超类型,所以您设置的内容不会限制任何东西)。
所以我认为这个决定是在对这两种方式有足够的经验之前做出的,并且做出了错误的选择。(这不是一个非常错误的选择;Either还是不错的。)