oxb*_*kes 12 monads for-loop scala either
我可以=在scala for-understanding中使用一个(如SLS第6.19节所述)如下:
假设我有一些功能String => Option[Int]:
scala> def intOpt(s: String) = try { Some(s.toInt) } catch { case _ => None }
intOpt: (s: String)Option[Int]
Run Code Online (Sandbox Code Playgroud)
然后我可以这样使用它
scala> for {
| str <- Option("1")
| i <- intOpt(str)
| val j = i + 10 //Note use of = in generator
| }
| yield j
res18: Option[Int] = Some(11)
Run Code Online (Sandbox Code Playgroud)
据我所知,这基本上相当于:
scala> Option("1") flatMap { str => intOpt(str) } map { i => i + 10 } map { j => j }
res19: Option[Int] = Some(11)
Run Code Online (Sandbox Code Playgroud)
也就是说,嵌入式生成器是一种将一个map注入一系列flatMap调用的方法.到现在为止还挺好.
我真正想要做的事情:使用与前一个使用Eithermonad的示例相似的for-comprehension.
但是,如果我们在类似的链中使用它,但这次使用Either.RightProjectionmonad/functor,它不起作用:
scala> def intEither(s: String): Either[Throwable, Int] =
| try { Right(s.toInt) } catch { case x => Left(x) }
intEither: (s: String)Either[Throwable,Int]
Run Code Online (Sandbox Code Playgroud)
然后使用:
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
^
Run Code Online (Sandbox Code Playgroud)
这个问题与右投影期望作为其flatMap方法的参数(即它期望a 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)
^
Run Code Online (Sandbox Code Playgroud)
但现在我倍加困惑.以下工作正常:
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)
Run Code Online (Sandbox Code Playgroud)
但这不是:
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 }
^
Run Code Online (Sandbox Code Playgroud)
我认为这些是等价的
=生成器来理解Either?你不能嵌入=for-comprehension 的事实与Jason Zaugg报告的这个问题有关; 解决方案是右偏Either(或创建与其同构的新数据类型).
对于你的巨大混乱,你错误地扩展了糖.贬低
for {
b <- x(a)
c <- y(b)
} yield z(c)
Run Code Online (Sandbox Code Playgroud)
是
x(a) flatMap { b =>
y(b) map { c =>
z(c) }}
Run Code Online (Sandbox Code Playgroud)
并不是
x(a) flatMap { b => y(b)} map { c => z(c) }
Run Code Online (Sandbox Code Playgroud)
因此你应该这样做:
scala> Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right map { y => y.toInt } }
res49: Either[Throwable,Int] = Right(1)
Run Code Online (Sandbox Code Playgroud)
for {
b <- x(a)
c <- y(b)
x1 = f1(b)
x2 = f2(b, x1)
...
xn = fn(.....)
d <- z(c, xn)
} yield w(d)
Run Code Online (Sandbox Code Playgroud)
被贬低了
x(a) flatMap { b =>
y(b) map { c =>
x1 = ..
...
xn = ..
(c, x1, .., xn)
} flatMap { (_c1, _x1, .., _xn) =>
z(_c1, _xn) map w }}
Run Code Online (Sandbox Code Playgroud)
所以在你的情况下,y(b)有Either没有map定义的结果类型.