所有Either cruft的交易是什么?

Mal*_*lio 41 scala

Either类似乎很有用,使用它的方法非常明显.但后来我看了API文档,我很困惑:

def joinLeft [A1 >: A, B1 >: B, C] (implicit ev: <:<[A1, Either[C, B1]]):
         Either[C, B1]
   Joins an Either through Left.

def joinRight [A1 >: A, B1 >: B, C] (implicit ev: <:<[B1, Either[A1, C]]):
         Either[A1, C]
   Joins an Either through Right.

def left : LeftProjection[A, B]
   Projects this Either as a Left.

def right : RightProjection[A, B]
   Projects this Either as a Right.
Run Code Online (Sandbox Code Playgroud)

我如何处理投影,如何调用连接?

Google只是向我指出了API文档.

这可能只是"不关注幕后人"的情况,但我不这么认为.我认为这很重要.

Did*_*ont 50

left并且right是重要的.Either在没有投影的情况下很有用(大多数情况下你会进行模式匹配),但投影非常值得关注,因为它们提供了更丰富的API.您将更少使用连接.

Either通常用来表示"适当的价值或错误".在这方面,它就像一个扩展Option.如果没有数据,则表示None您有错误. Option有一个丰富的API.同样可以提供上Either,只要我们知道,无论是哪种,哪一个是结果,哪一个是错误.

leftright投影就是这样说的.它是Either,加上增加的知识,该值分别在左侧或右侧,另一个是错误.

例如,Option你可以映射,所以opt.map(f)返回Optionf应用,它的值opt,如果它有一个,仍然None如果optNone.在左侧投影中,f如果它是a Left,它将应用于左侧的值,如果是a ,则将其保持不变Right.观察签名:

  • LeftProjection[A,B],map[C](f: A => C): Either[C,B]
  • RightProjection[A,B],map[C](f: B => C): Either[A,C].

left并且right只是当你想要使用一个通常的API例程时,说出哪一方被认为是值的方法.

替代方案可能是:

  • 设置一个约定,就像在Haskell中一样,在语法上有很强的理由将值放在正确的位置.如果要在另一侧应用方法(您可能希望使用map例如更改错误),请执行swap之前和之后的操作.
  • 后缀方法名称左或右(可能只是L和R).这会妨碍使用理解.随着for内涵(flatMap事实上,但对于符号是相当方便的)Either是(检查)异常的替代品.

现在加入.左和右意味着与投影相同,它们与投影密切相关flatMap.考虑joinLeft.签名可能令人费解:

joinLeft [A1 >: A, B1 >: B, C] (implicit ev: <:<[A1, Either[C, B1]]):
         Either[C, B1]
Run Code Online (Sandbox Code Playgroud)

A1并且B1在技​​术上是必要的,但对理解并不重要,让我们简化

joinLeft[C](implicit ev: <:<[A, Either[C, B])
Run Code Online (Sandbox Code Playgroud)

什么隐含的意思是,如果该方法只能被称为A是一个Either[C,B].该方法一般不可用Either[A,B],但仅适用于Either[Either[C,B], B].与左投影一样,我们认为值在左边(适合joinRight).连接的作用是扁平化(想想flatMap).当一个连接时,不关心错误(B)是在内部还是外部,我们只想要[C,B].所以左(左(c))产生左(c),左(右(b))和右(b)产生右(b).与flatMap的关系如下:

joinLeft(e) = e.left.flatMap(identity)
e.left.flatMap(f) = e.left.map(f).joinLeft
Run Code Online (Sandbox Code Playgroud)

Option相当于将努力上Option[Option[A]], Some(Some(x))将产生Some(x)两个Some(None)None将产生None.它可以写成o.flatMap(身份).注意,它Option[A]是同形的Either[A,Unit](如果你使用左投影和连接),也是Either[Unit, A](使用右投影).


Kev*_*ght 20

暂时忽略连接,投影是一种允许您使用an Either作为monad的机制.可以把它想象成将左侧或右侧抽成一个Option,但不会丢失另一侧

与往常一样,这可能通过一个例子更有意义.所以想象你有一个Either[Exception, Int]并希望将其转换Exception为a String(如果存在)

val result = opReturningEither
val better = result.left map {_.getMessage}
Run Code Online (Sandbox Code Playgroud)

这将映射到结果的左侧,给你一个 Either[String,Int]


Ben*_*mes 14

joinLeftjoinRight让你"变平"的嵌套Either:

scala> val e: Either[Either[String, Int], Int] = Left(Left("foo"))
e: Either[Either[String,Int],Int] = Left(Left(foo))

scala> e.joinLeft
res2: Either[String,Int] = Left(foo)
Run Code Online (Sandbox Code Playgroud)

编辑:我对这个问题的回答显示了如何使用投影的一个例子,在这种情况下,将一系列Eithers 折叠在一起,没有模式匹配或调用isLeftisRight.如果你熟悉如何在Option没有匹配或调用的情况下使用isDefined它,那就是类似的.


虽然好奇地看着Either的当前来源,但我看到了joinLeft并且joinRight通过模式匹配来实现.但是,我偶然发现了这个旧版本的源代码,并发现它用于使用投影实现连接方法:

def joinLeft[A, B](es: Either[Either[A, B], B]) =
  es.left.flatMap(x => x)
Run Code Online (Sandbox Code Playgroud)

  • 这不是你可能想要一个,而是你可能得到一个,加入可以让你摆脱它.假设你在A的某种通用容器上有一个函数,它会返回一个Either [A,E],因为有可能失败.假设您的特定容器包含[YourData,E],因为数据是可能失败的进程的结果.然后你得到一个[Either [YourData,E],E],你可能想要加入,因为你不关心在构建数据(内部数据)或检索数据(外部数据)时是否发生了错误. (4认同)