【发布时间】:2012-05-28 03:24:48
【问题描述】:
我可以在 scala 中使用= 进行理解(如6.19 of the SLS 部分所述),如下所示:
选项
假设我有一些函数String => Option[Int]:
scala> def intOpt(s: String) = try { Some(s.toInt) } catch { case _ => None }
intOpt: (s: String)Option[Int]
那我就可以这样用了
scala> for {
| str <- Option("1")
| i <- intOpt(str)
| val j = i + 10 //Note use of = in generator
| }
| yield j
res18: Option[Int] = Some(11)
据我了解,这基本上等同于:
scala> Option("1") flatMap { str => intOpt(str) } map { i => i + 10 } map { j => j }
res19: Option[Int] = Some(11)
也就是说,嵌入式生成器是一种将map 注入flatMap 调用序列的方法。到目前为止一切顺利。
Either.RightProjection
我真正想做的事情:使用与前面使用Either monad 的示例类似的理解。
但是,如果我们在类似的链中使用它,但这次使用Either.RightProjection monad/functor,它就不起作用了:
scala> def intEither(s: String): Either[Throwable, Int] =
| try { Right(s.toInt) } catch { case x => Left(x) }
intEither: (s: String)Either[Throwable,Int]
然后使用:
scala> for {
| str <- Option("1").toRight(new Throwable()).right
| i <- intEither(str).right //note the "right" projection is used
| val j = i + 10
| }
| yield j
<console>:17: error: value map is not a member of Product with Serializable with Either[java.lang.Throwable,(Int, Int)]
i <- intEither(str).right
^
问题与右投影期望作为其flatMap 方法的参数的函数有关(即,它期望R => Either[L, R])。但是修改为不在第二个生成器上调用right,它仍然不会编译。
scala> for {
| str <- Option("1").toRight(new Throwable()).right
| i <- intEither(str) // no "right" projection
| val j = i + 10
| }
| yield j
<console>:17: error: value map is not a member of Either[Throwable,Int]
i <- intEither(str)
^
大混乱
但现在我变得更加困惑。以下工作正常:
scala> for {
| x <- Right[Throwable, String]("1").right
| y <- Right[Throwable, String](x).right //note the "right" here
| } yield y.toInt
res39: Either[Throwable,Int] = Right(1)
但这不是:
scala> Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right } map { y => y.toInt }
<console>:14: error: type mismatch;
found : Either.RightProjection[Throwable,String]
required: Either[?,?]
Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right } map { y => y.toInt }
^
我认为这些是等价的
- 这是怎么回事?
- 如何将
=生成器嵌入到Either的 for comprehension 中?
【问题讨论】:
-
小注:理解中不需要
val。只是j = i + 10工作正常。但是,我没有理由不将计算放在yield的右侧:} yield i + 10。相似之处:在第一个地图示例中,`map { j => j }` 没有任何作用,可以省略。 -
我会像这样定义
intOpt和intEither:def intOpt(s: String) = allCatch opt s.toInt和def intEither(s: String) = allCatch either s.toInt(已经完成import scala.util.control.Exception._)。 -
@user unknown - 这只是一个例子;在我的用例中,我确实想在
flatMaps 序列中嵌入一个map
标签: scala for-loop monads either