Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 为什么“Left”和“Right”有两个类型参数?_Scala_Either - Fatal编程技术网

Scala 为什么“Left”和“Right”有两个类型参数?

Scala 为什么“Left”和“Right”有两个类型参数?,scala,either,Scala,Either,我知道如果不破坏现有的代码,现在就很难进行更改,但我想知道为什么当初是这样做的 为什么不只是: 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] 这里有什么我没有看到的缺点吗?我发现你的计划没有什么有意义的缺点。在过去八年左右的时间里,我使用了我自己的或变体,这与您在另一个名称下描

我知道如果不破坏现有的代码,现在就很难进行更改,但我想知道为什么当初是这样做的

为什么不只是:

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]

这里有什么我没有看到的缺点吗?

我发现你的计划没有什么有意义的缺点。在过去八年左右的时间里,我使用了我自己的
变体,这与您在另一个名称下描述的完全相同(
Ok[+Y,+N]
,其中
Yes[+Y]
No[+N]
作为替代名称)。(历史笔记:我开始的时候
或者
都不是右倾的,我想要的东西是右倾的;但后来我继续使用我的版本,因为只有一半的类型更方便。)

我所发现的唯一一种情况是,模式匹配一个分支,而不再能够访问另一个分支的类型信息

def foo[A,B:Typeclass](e:one[A,B])=
隐式[Typeclass[B]].whatever()
//这很有效
我的比赛{
案例一:左[l,R]=>foo(l)
案例r:右[L,r]=>foo(r)
}
def条[N,Y:Typeclass](o:Ok[N,Y])=
隐式[Typeclass[Y]].whatever()
//这不管用
明克火柴{
案例y:是[y]=>条(y)//这很好
案例n:No[n]=>bar(n)//Y==Nothing!
}
然而,我从来没有这样做过。我可以使用
o
来获得正确的类型。所以没关系!其他一切都更容易(如模式匹配和更改一个案例而不是另一个案例…您不需要
案例左(l)=>Left(l)
,它会重建
,除了切换无人居住分支的类型之外,没有其他原因)

还有其他一些情况(例如,预先设置类型)看起来应该很重要,但实际上几乎不可能做到这一点(例如,因为协方差会找到常见的超类型,所以设置的内容不会约束任何内容)


因此,我认为这一决定是在这两种方法有足够的经验之前做出的,并且做出了错误的选择。(这不是一个非常错误的选择;
或者
仍然是不错的。)

不确定这个答案与Scala有多大关系,但肯定是在Haskell,这显然是Scala的
或者
被借用的地方,因此这可能是Scala这样做的最好的历史原因

或者
是规范的,即对于您拥有的任何类型的
A
B

  • 类型
    EitherA,B≈ A.⊕ B
  • 两个共投影
    LeftA,B:A->A⊕B
    右侧A,B:B->A⊕B
  • 这样,对于任何类型的
    Y
    和任何函数
    fA:A->Y
    fB:B->Y
    ,只存在一个函数
    f:A⊕属性为
    fA=f的B->Y
    ∘ 左A、B和fB=f∘ 右侧A、B
为了从数学上表述这一点,让特定的
留下的信息显式地表达出来是非常有帮助的,因为否则态射的域都不清楚。在Scala中,由于隐式协变变换,这可能是不必要的,但在数学和Haskell中都不是

在Haskell中,这根本不是一个问题,因为类型推断将自动执行所需的操作:

GHCi,8.6.5版:http://www.haskell.org/ghc/ :? 求救 已从/tmp/haskell stack GHCi/2a3bbd58/GHCi脚本加载GHCi配置 前奏曲>让右2=右2 前奏曲>让左42=左42.0 前奏曲>(+)右2左42 左42.0
显然,与Scala不同的是,Haskell只将未指定的第二个参数
left42
作为类型变量(除非启用了单态限制),因此您可以在以后的任何上下文中使用它,对于任何类型
R
,都需要双R
。当然,这也有可能明确地表达出来

right2 :: Either a Int
right2 = Right 2

left42 :: Either Double a
left42 = Left 42

main :: IO ()
main = print $ (+) <$> right2 <*> left42
right2::一个Int
右2=右2
left42::要么是双a
左42=左42
main::IO()
main=打印$(+)right2 left42

这在Scala中当然也是可能的。

注意,有人问了同样的问题,关于这里的
Try
,但从未得到满意的答案:在贡献者频道上相关。不清楚为什么最初的设计是这样的,但似乎没有进行更改,因为它可能会破坏代码(这不是很糟糕),但也会破坏交叉编译(非常糟糕!),当然,这可以通过使用
scala collection compat
library之类的方法来解决,但这在当时似乎不是一件事。谢谢你的回答,雷克斯!看到如此明确地梳理出细微差别是非常令人满意的。它还可以在将来向更有效的模式过渡,即使现在很难做到这一点。我们经历了从非右倾到右倾的转变。似乎可以启用类似的转换,将其转换为与Ok解决方案相同的类型形状。谢谢,Rex。我只能接受一个答案,但这个答案也很有价值。考虑到
scala的原始作者,
也是Scalaz的原始作者,这可能是对标题中“为什么”问题的一个很好的回答。