为什么Scala选择“Product”类型?为了“为了”涉及 Either 和值定义的表达式
如果我使用 Option 创建一个带有值定义的 for 理解,它会按预期工作:
scala> for (a <- Some(4); b <- Some(5); val p = a * b) yield p
res0: Option[Int] = Some(20)
如果我没有值定义,则使用 Either 做同样的事情会起作用:
scala> for (a <- Right(4).right; b <- Right(5).right) yield a * b
res1: Either[Nothing,Int] = Right(20)
但是如果我使用值定义,scala 似乎会推断出错误的容器类型理解:
scala> for (a <- Right(4).right; b <- Right(5).right; val p = a * b) yield p
<console>:8: error: value map is not a member of Product with Serializable with Either[Nothing,(Int, Int)]
for (a <- Right(4).right; b <- Right(5).right; val p = a * b) yield p
^
为什么要这样做?有哪些方法可以解决这种行为?
If I create a for comprehension with a value definition with Option, it works as expected:
scala> for (a <- Some(4); b <- Some(5); val p = a * b) yield p
res0: Option[Int] = Some(20)
Doing the same thing with Either works if i have no value definition:
scala> for (a <- Right(4).right; b <- Right(5).right) yield a * b
res1: Either[Nothing,Int] = Right(20)
But if i used the value definition, scala seems to infer the wrong container type for the for comprehension:
scala> for (a <- Right(4).right; b <- Right(5).right; val p = a * b) yield p
<console>:8: error: value map is not a member of Product with Serializable with Either[Nothing,(Int, Int)]
for (a <- Right(4).right; b <- Right(5).right; val p = a * b) yield p
^
Why does it do this? What ways around this behavior are available?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题来自
val p = a*b
如果您编写更简单的
for (a <- Right(4).right; b <- Right(5).right) 产量 a*b
它会编译并获得正确的结果。
您的问题有两个原因
首先,
Either
投影map
和flatMap
没有通常的签名,即对于在 a 中定义的例程 map 和 flatMap泛型类M[A]
,(A => B) => M[B]
和(A => M[B]) => M[B]
。例程中定义的M[A]
是Either[A,B].RightProjection
,但在结果和参数中,我们有Either[A,B] ]
而不是投影。其次,for 理解中
val p = a*b
的翻译方式。 Scala 参考,6.19 第 90 页:让我们稍微简化一下代码,删除
a <-
。此外,将b
和p
重命名为p
和pp
以更接近重写规则,其中pp
代表p'
。a
应该在范围内for(p <- Right(5).right; val pp = a*p) 产生 pp
遵循规则,我们必须替换生成器 + 定义。周围是什么,
for(
and)yield pp
,没有改变。内部的for被重写为一个简单的map,
这就是问题所在。
Right(5).right.map(...)
的类型为Either[Nothing, (Int,Int)]
,而不是Either.RightProjection[没有任何东西,(Int,Int)]
正如我们所希望的那样。它在外部 for 中不起作用(它也转换为map
。Either
上没有map
方法,它是在投影上定义的如果您仔细查看错误消息,它会这样说,即使它提到
Product
和Serialized
,它也会说它是Either[Nothing, (国际, Int)]
,并且没有在其上定义映射对(Int, Int)
直接来自重写规则。for 理解旨在在尊重正确的情况下正常工作 。通过使用
Either
投影(也有其优点)的技巧,我们得到了这个问题。The problems comes from
val p = a*b
If you write the simpler
for (a <- Right(4).right; b <- Right(5).right) yield a*b
it compiles and you get the proper result.
Your problem has two causes
First, the
Either
projectionsmap
andflatMap
do not have the usual signature , namely for routines map and flatMap defined in a generic classM[A]
,(A => B) => M[B]
and(A => M[B]) => M[B]
. TheM[A]
the routine are defined in isEither[A,B].RightProjection
, but in results and argument, we haveEither[A,B]
and not the projection.Second, the way
val p = a*b
in the for comprehension is translated. Scala Reference, 6.19 p 90:Let's simplify the code just a little bit, dropping the
a <-
. Also,b
andp
renamed top
andpp
to be closer to the rewrite rule, withpp
forp'
.a
supposed to be in scopefor(p <- Right(5).right; val pp = a*p) yield pp
following the rule, we have to replace the generator + definition. What is around that,
for(
and)yield pp
, unchanged.The inner for is rewritten to a simple map
Here is the problem. The
Right(5).right.map(...)
is of typeEither[Nothing, (Int,Int)]
, notEither.RightProjection[Nothing, (Int,Int)]
as we would want. It does not work in the outer for (which converts to amap
too. There is nomap
method onEither
, it is defined on projections only.If you look closely at your error message, it says so, even if it mentions
Product
andSerializable
, it says that it is anEither[Nothing, (Int, Int)]
, and that no map is defined on it. The pair(Int, Int)
comes directly from the rewrite rule.The for comprehension is intended to work well when respecting the proper signature. With the trick with
Either
projections (which has its advantages too), we get this problem.