繁体   English   中英

将无折叠集合作为起始值

[英]Fold collection with None as start value

我想折叠一个集合或Y并返回一个选项[X]。 我想从无。开始。 像这样...

def f(optX: Option[X], y: Y): Option[X]
val optX = collectionOfY.fold(None) { case (prev, y) => f(prev,y) }

添加不需要的类型以使其更清晰

val optX: Option[X] = collectionOfY.fold(None) { case (prev: Option[X], y: Y) => f(prev,y) }

但是,编译器无法正确计算出类型,我必须像这样编写它

val xx: Option[X] = None
val optX = collectionOfY.fold(xx) { case (prev, y) => f(prev,y) }

写这篇文章的神奇Scala语法是什么?

谢谢彼得

只需使用foldLeft和以下任何一项

... foldLeft(Option.empty[X]) ...... foldLeft(None: Option[X]) ...... foldLeft[Option[X]](None) ...

毕竟, fold只是调用foldLeft 当你的A1确实是A的超类型时,你真的只想使用fold ,如果确实如此,你可以使用如上所述的fold ,编译器将正确地知道类型。

例如, Option[List[Int]] <: Option[Seq[Int]]的协方差,所以我们在这里得不到Any一个:

List(Some(List(1,2,3))).fold[Option[Seq[Int]]](None)((_, _) => Some(Seq(1)))

> res2: Option[Seq[Int]] = Some(List(1))

最后,如果你确实知道Option[X]将是Y的超类型,那么在Y的类型声明中明确说明 - 即Y <: Option[X] ,那么你可以使用fold与上面给出的解决方案。

请参阅何时应该使用.empty与单例空实例? 进行相关讨论。

此行为是合乎逻辑的,因为fold定义为

def fold[A1 >: A](z: A1)(op: (A1, A1) ⇒ A1): A1

这意味着起始参数是A的超类型,但NoneOption[T]的超类型。 如果直接指定类型(如第二个示例中所示),则编译器有足够的信息来确定折叠的返回类型。

一种可能的解决方法是指定集合头部的交互结果,以None作为起点,并将其与集合的其余部分折叠(添加对Nil的检查):

val optX = collectionOfY.match {
  case Nil => None
  case x:xs => xs.fold(f(None,x)) {case (prev,y) => f(prev,y) }
}

正如上面的注释中所指出的,首选的解决方案是更改传递给Option.fold的第一个参数,以避免使用None并改为使用Option.empty[X]

val optX = collectionOfY.fold(Option.empty[X]) { case (prev, y) => f(prev,y) }

Scala编译器无需投诉即可接受此操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM