for {
a <- Some(1)
b <- Some(2)
} yield (a, b)
返回Some((1, 2))
for {
a <- Right(1).right
b <- Left(2).left
} yield (a, b)
返回Left((1, 2))
现在我想在for comprehension中分解元组。
for {
(a, b) <- Some((1, 2))
(c, d) <- Some((3, 4))
} yield (a, b, c, d)
返回Some((1, 2, 3, 4))
for {
(a, b) <- Right((1, 2)).right
(c, d) <- Left((3, 4)).left
} yield (a, b, c, d)
无法编译:
error: constructor cannot be instantiated to expected type;
found : (T1, T2)
required: scala.util.Either[Nothing,(Int, Int)]
(a, b) <- Right((1, 2)).right
error: constructor cannot be instantiated to expected type;
found : (T1, T2)
required: scala.util.Either[(Int, Int),Nothing]
为什么这最后一个例子不起作用?有什么区别?
答案 0 :(得分:6)
这是一个错误:
withFilter()
被调用(一些文档引用filter()
,但在2.8中已经改变了,这与类型推断有关。
withFilter()
用于for(a <- b if c)
之类的内容,但根据6.19,在这种情况下不应使用它。
后一个错误在SI-1336: spec requires type checking of for-comprehension to consider refutability中捕获,已开放七年(2008年)。
也许下一代会找到修复。
请参阅why does filter have to be defined for pattern matching in a for loop in scala?
答案 1 :(得分:4)
因为(Any,Any)&lt; - 的生成器都不是“无可辩驳的”过滤器被添加到desugared代码(why does filter have to be defined for pattern matching in a for loop in scala?)中,导致:
Right((1, 2)).right.filter { case (a, b) => true; case _ => false }.flatMap({
case(a, b) => Left((3, 4)).left.filter { case (c, d) => true; case _ => false }.map({case (c, d) =>
(a, b, c, d)
})
})
过滤器是编译错误发生的地方,因为Right的过滤器方法看起来像这样(左边的类似):
def filter[X](p: B => Boolean): Option[Either[X, B]] = e match {
case Left(_) => None
case Right(b) => if(p(b)) Some(Right(b)) else None
}
这意味着编译器正在尝试执行以下操作:
(T1, T2) match {
case Left(_) => None
case Right(b) => if(p(b)) Some(Right(b)) else None
}
失败,因为(T1,T2)无法转换为[A,B](右侧扩展),其中A为Nothing,B为(Int,Int)。
您可以使用以下方法获得与此相近的内容:
for {
a <- Right((1, 2)).right
b <- Left((3, 4)).left
} yield (a, b) match {
case ((c, d), (e, f)) => (c, d, e, f)
case _ =>
}
答案 2 :(得分:3)
这可能是表达式的限制。翻译
for {
(a, b) <- Some((1, 2))
(c, d) <- Some((3, 4))
} yield (a, b, c, d)
到
Some((1, 2)).flatMap({case(a, b) =>
Some((3, 4)).map({case (c, d) =>
(a, b, c, d)
})
})
双向工作。使用Either
表达式,只有map / flatMap
版本有效。
for {
(a, b) <- Right((1, 2)).right
(c, d) <- Left((3, 4)).left
} yield (a, b, c, d)
Right((1, 2)).right.flatMap({
case(a, b) => Left((3, 4)).left.map({case (c, d) =>
(a, b, c, d)
})
})
我不建议使用Either
,而是使用\/
类型
scalaz。 http://eed3si9n.com/learning-scalaz/Either.html Either
不是
左,右倾,这是一个问题,因为它没有指明
错误或值的位置。