简体   繁体   English

将无折叠集合作为起始值

[英]Fold collection with None as start value

I want to fold a collection or Y's and return an Option[X]. 我想折叠一个集合或Y并返回一个选项[X]。 I want to start with None. 我想从无。开始。 Like this... 像这样...

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

adding unneeded types to make it clearer 添加不需要的类型以使其更清晰

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

However, the compiler can not figure out the type properly and I have to write it like this 但是,编译器无法正确计算出类型,我必须像这样编写它

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

What is the magic Scala syntax to write this? 写这篇文章的神奇Scala语法是什么?

Thanks Peter 谢谢彼得

Just use foldLeft and any of the following 只需使用foldLeft和以下任何一项

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

After all, fold just calls foldLeft . 毕竟, fold只是调用foldLeft You only really want to use fold when your A1 really is a super-type of A , if that really is the case then you can use fold as above and the compiler will know the type correctly. 当你的A1确实是A的超类型时,你真的只想使用fold ,如果确实如此,你可以使用如上所述的fold ,编译器将正确地知道类型。

For example, Option[List[Int]] <: Option[Seq[Int]] by covariance so we don't get an Any here: 例如, 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))

Finally, if you do indeed know Option[X] will be a super-type of Y then say this explicitly in the type declaration of Y - ie Y <: Option[X] , then you can use fold with the solutions given above. 最后,如果你确实知道Option[X]将是Y的超类型,那么在Y的类型声明中明确说明 - 即Y <: Option[X] ,那么你可以使用fold与上面给出的解决方案。

See When should .empty be used versus the singleton empty instance? 请参阅何时应该使用.empty与单例空实例? for a related discussion. 进行相关讨论。

This behavior is logical, because fold is defined as 此行为是合乎逻辑的,因为fold定义为

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

that means the starting parameter is a supertype of A , but None is's a supertype of Option[T] . 这意味着起始参数是A的超类型,但NoneOption[T]的超类型。 If you specify the type directly (like in your second example) then the compiler has enough information to figure out the return type of fold. 如果直接指定类型(如第二个示例中所示),则编译器有足够的信息来确定折叠的返回类型。

One possible workaround is to specify the result of interaction of head of your collection with None as a starting point, and fold it with the rest of the collection (adding a check for Nil ): 一种可能的解决方法是指定集合头部的交互结果,以None作为起点,并将其与集合的其余部分折叠(添加对Nil的检查):

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

As was pointed out in the comments above, the preferred solution is change the first parameter passed to Option.fold to avoid the use of None and use Option.empty[X] instead. 正如上面的注释中所指出的,首选的解决方案是更改传递给Option.fold的第一个参数,以避免使用None并改为使用Option.empty[X]

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

The Scala compiler accepts this without complaint. Scala编译器无需投诉即可接受此操作。

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

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