Search code examples
scalacollectionsfoldscala-option

Fold collection with None as start value


I want to fold a collection or Y's and return an Option[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?

Thanks Peter


Solution

  • Just use foldLeft and any of the following

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

    After all, fold just calls 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.

    For example, Option[List[Int]] <: Option[Seq[Int]] by covariance so we don't get an Any here:

    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 - i.e. Y <: Option[X], then you can use fold with the solutions given above.

    See When should .empty be used versus the singleton empty instance? for a related discussion.