正确的投影混淆(理解脱糖) [英] scala Either.RightProjection confusion (for comprehension de-sugaring)
问题描述
我可以在scala for-comprehension中使用 =
(如 6.19 的SLS )如下所示:
h2>
假设我有一些函数 String =>选项[Int]
:
scala> def intOpt(s:String)= try {Some(s.toInt)} catch {case _ =>无}
intOpt:(s:String)选项[Int]
然后我可以使用它因此
scala>为{
| str< - Option(1)
|我< - intOpt(str)
| val j = i + 10 //注意在生成器
|中使用= }
|产量j
res18:Option [Int] =一些(11)
这是我的理解这基本上相当于:
scala>选项(1)flatMap {str => intOpt(str)} map {i => i + 10} map {j => j}
res19:Option [Int] =一些(11)
也就是说,嵌入式生成器是一种将 map
注入到 flatMap
调用序列中的方法。到目前为止这么好。
或者.RightProjection
我真正想做的事:使用与前面使用任一
monad 的示例类似的理解。
<但是,如果我们在类似的链中使用它,但是这次使用 Either.RightProjection
monad / functor,它不起作用:
scala> def intEither(s:String):或者[Throwable,Int] =
|尝试{Right(s.toInt)} catch {case x => Left(x)}
intEither:(s:String)[Throwable,Int]
然后使用:
scala>为{
| str< - Option(1)。toRight(new Throwable())right
|我< - intEither(str).right //注意右投影使用
| val j = i + 10
| }
| (java.lang.Throwable,(Int,Int)]
i< - intEither(str);返回值为j
< console>:17:error:value map不是Product的一个成员, ).right
^
这个问题与这个函数有关,投影期望作为其 flatMap
方法的一个参数(即它期望一个 R => [L,R]
)。但修改为不在第二个生成器上调用 right ,它仍然不会编译。
阶>为{
| str< - Option(1)。toRight(new Throwable())right
|我< - intEither(str)//否rightprojection
| val j = i + 10
| }
| yield j
< console>:17:error:value map不是Either [Throwable,Int]
i < - intEither(str)
^
的成员。 code>
超级混乱
但现在我倍感困惑。下面的例子很好:
scala>为{
| x< - 右[Throwable,String](1)。右
| y< - 右[Throwable,String](x).right //注意这里的right
| } yield y.toInt
res39:或者[Throwable,Int] = Right(1)
但是这不是:
scala> Right [Throwable,String](1)。right flatMap {x =>右[Throwable,String](x).right} map {y => y.toInt}
< console>:14:error:type mismatch;
found:Either.RightProjection [Throwable,String]
required:[?,?]
Right [Throwable,String](1)。right flatMap {x =>右[Throwable,String](x).right} map {y => y.toInt}
^
我认为这些是相同的
- 发生了什么事情?
- 如何嵌入
=
在>
?
不能将 =
嵌入到for-comprehension中的事实与这个问题由Jason Zaugg报道;解决的办法是右偏或者
(或者创建一个与它同构的新数据类型)。
巨大的困惑,你不正确地扩大了糖。 (
b < - x(a)
c < - y(b)的解除/ b
$ b
)
} yield z(c)
是
x(a)flatMap {b =>
y(b)map {c =>
z(c)}}
而不是
x(a)flatMap {b => y(b)} map {c => z(c)}
因此您应该这样做:
scala> Right [Throwable,String](1)。right flatMap {x =>右[Throwable,String](x).right map {y => y.toInt}}
res49:[Throwable,Int] = Right(1)
关于desugaring(`j = i + 10`问题)的更多乐趣
对于{
b < - x (a)
c <-y(b)
x1 = f1(b)
x2 = f2(b,x1)
...
xn = fn (.....)
d <-z(c,xn)
}得到w(d)
被解析成
x(a)flatMap {b =>
y(b)map {c =>
x1 = ..
...
xn = ..
(c,x1,..,xn)
} flatMap {(_c1,_x1,。 。,_xn)=>
z(_c1,_xn)map w}}
$ c> y(b)的结果类型为或者
不包含 map
定义。
I can use an =
in a scala for-comprehension (as specified in section 6.19 of the SLS) as follows:
Option
Suppose I have some function String => Option[Int]
:
scala> def intOpt(s: String) = try { Some(s.toInt) } catch { case _ => None }
intOpt: (s: String)Option[Int]
Then I can use it thus
scala> for {
| str <- Option("1")
| i <- intOpt(str)
| val j = i + 10 //Note use of = in generator
| }
| yield j
res18: Option[Int] = Some(11)
It was my understanding that this was essentially equivalent to:
scala> Option("1") flatMap { str => intOpt(str) } map { i => i + 10 } map { j => j }
res19: Option[Int] = Some(11)
That is, the embedded generator was a way of injecting a map
into a sequence of flatMap
calls. So far so good.
Either.RightProjection
What I actually want to do: use a similar for-comprehension as the previous example using the Either
monad.
However, if we use it in a similar chain, but this time using the Either.RightProjection
monad/functor, it doesn't work:
scala> def intEither(s: String): Either[Throwable, Int] =
| try { Right(s.toInt) } catch { case x => Left(x) }
intEither: (s: String)Either[Throwable,Int]
Then use:
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
^
The issue has something to do with the function that a right-projection expects as an argument to its flatMap
method (i.e. it expects an R => Either[L, R]
). But modifying to not call right
on the second generator, it still won't compile.
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)
^
Mega-Confusion
But now I get doubly confused. The following works just fine:
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)
But this does not:
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 }
^
I thought these were equivalent
- What is going on?
- How can I embed an
=
generator in a for comprehension across anEither
?
The fact that you cannot embed the =
in the for-comprehension is related to this issue reported by Jason Zaugg; the solution is to Right-bias Either
(or create a new data type isomorphic to it).
For your mega-confusion, you expanded the for sugar incorrectly. The desugaring of
for {
b <- x(a)
c <- y(b)
} yield z(c)
is
x(a) flatMap { b =>
y(b) map { c =>
z(c) }}
and not
x(a) flatMap { b => y(b)} map { c => z(c) }
Hence you should have done this:
scala> Right[Throwable, String]("1").right flatMap { x => Right[Throwable, String](x).right map { y => y.toInt } }
res49: Either[Throwable,Int] = Right(1)
More fun about desugaring (the `j = i + 10` issue)
for {
b <- x(a)
c <- y(b)
x1 = f1(b)
x2 = f2(b, x1)
...
xn = fn(.....)
d <- z(c, xn)
} yield w(d)
is desugared into
x(a) flatMap { b =>
y(b) map { c =>
x1 = ..
...
xn = ..
(c, x1, .., xn)
} flatMap { (_c1, _x1, .., _xn) =>
z(_c1, _xn) map w }}
So in your case, y(b)
has result type Either
which doesn't have map
defined.
这篇关于正确的投影混淆(理解脱糖)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!