srp*_*ish 14 scala type-inference for-comprehension
如果我使用Option创建一个带有值定义的for comprehension,它将按预期工作:
scala> for (a <- Some(4); b <- Some(5); val p = a * b) yield p
res0: Option[Int] = Some(20)
Run Code Online (Sandbox Code Playgroud)
如果我没有值定义,则使用Either做同样的事情:
scala> for (a <- Right(4).right; b <- Right(5).right) yield a * b
res1: Either[Nothing,Int] = Right(20)
Run Code Online (Sandbox Code Playgroud)
但是如果我使用了值定义,scala似乎推断了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
^
Run Code Online (Sandbox Code Playgroud)
为什么这样做?有哪些方法可以解决这种问题?
Did*_*ont 19
问题来自于val p = a*b
如果你写得更简单
for(a < - Right(4).right; b < - Right(5).right)产生a*b
它编译,你得到了正确的结果.
你的问题有两个原因
首先,Either投影map并flatMap没有通常的签名,即用于在泛型类中定义的例程map和flatMap M[A],(A => B) => M[B]以及(A => M[B]) => M[B].在M[A]常规的定义在IS Either[A,B].RightProjection,但结果和论证,我们有Either[A,B]和没有的投影.
其次,val p = a*b翻译了理解的方式.Scala参考,6.19 p 90:
生成器p < - e后跟值定义p'= e'被转换为下面的值对生成器,其中x和x'是新名称:
(p,p?) <- for(x@p<-e) yield {val x?@p? = e?; (x,x?)}
Run Code Online (Sandbox Code Playgroud)
让我们简单地简化一下代码吧a <-.此外,b并p更名为p和pp更接近重写规则,以pp对p'.a应该在(p < - Right(5).right; val pp = a*p)yield pp的范围内
遵循规则,我们必须替换生成器+定义.这是什么,for(并且)yield pp没有改变.
for((p, pp) <- for(x@p <- Right(5).right) yield{val xx@pp = a*p; (x,xx)}) yield pp
Run Code Online (Sandbox Code Playgroud)
内部for被重写为一个简单的地图
for((p, pp) <- Right(5).right.map{case x@p => val xx@pp = a*p; (x,xx)}) yield pp
Run Code Online (Sandbox Code Playgroud)
这是问题所在.该Right(5).right.map(...)类型是Either[Nothing, (Int,Int)],不是Either.RightProjection[Nothing, (Int,Int)]因为我们想.它在外部for(也转换为a)中不起作用map.没有map方法Either,它仅在投影上定义.
如果您在您的错误信息仔细一看,它是这么说的,即使它提到Product和Serializable,它说,它是一个Either[Nothing, (Int, Int)],而没有地图上定义.该对(Int, Int)直接来自重写规则.
理解是为了在尊重适当的签名时运作良好.通过Either投影技巧(也有其优势),我们遇到了这个问题.
| 归档时间: |
|
| 查看次数: |
6039 次 |
| 最近记录: |