为什么使用元组的Scala表达式无法编译?

时间:2011-04-29 11:32:59

标签: scala compiler-errors

使用Scala 2.8.1,编译:

val t = (40, 2)

println(for ((i, j) <- List(t)) yield i + j)

val e: Either[String, (Int, Int)] = Right(t)
println(e.right.map {
  case (i, j) => i + j
})
println(for ((i, j) <- e.right) yield i + j)

给出了这个:

test.scala:9: error: constructor cannot be instantiated to expected type;
 found   : (T1, T2)
 required: Either[Nothing,(Int, Int)]
println(for ((i, j) <- e.right) yield i + j)

根据Scala中的 Programming ,for表达式应该等同于map / case表达式,但只有后者才能编译。我做错了什么,我应该怎么做?

2 个答案:

答案 0 :(得分:11)

实际上,这不是完全正在发生的翻译。您可以参考this answer获取更完整的指南,但即使在那里也没有明确提及此案例。

对于使用模式匹配的理解,过滤不匹配的情况会发生什么。例如,

for((i, j) <- List((1, 2), 3)) yield (i, j)

将返回List((1, 2)): List[(Any, Any)],因为首先调用withFilter。现在,Either似乎没有withFilter,所以它会使用filter,而这里是理解的实际翻译:

e.right.filter { case (i, j) => true; case _ => false }.map { case (i, j) => i + j }

这给出了完全相同的错误。问题是e.right会返回RightProjection,但filter上的RightProjection[A, B]会返回Option[Either[Nothing, B]]

原因是没有“空”Either(或RightProjection)这样的东西,所以需要将其结果封装在Option上。

说了这么多,看看for-comprehension水平真是令人惊讶。我认为正确的做法是让filter返回某种过滤后的投影。

答案 1 :(得分:2)

Right不会返回您可能期望的选项,而是返回RightProjection。这解决了它:

println(for ((i, j) <- e.right.toOption) yield i + j)