12

I'm looking for a more general solution which exploits monads (and monoids possibly) to achieve the same as if( xs.contains(None) ) None else Some(xs.flatten) does for xs of type Seq[Option[A]].

How can I do that with Scalaz? I feel like I'm missing something evident.

Nikita Volkov
  • 42,792
  • 11
  • 94
  • 169

1 Answers1

14

Having two monads is both not enough (for M) and more than enough (for N)—which adds up to not enough, of course—but if M has a Traverse instance and N has an Applicative instance, you can use sequence. For example:

import scalaz._, Scalaz._

def foo[A](xs: List[Option[A]]): Option[List[A]] = xs.sequence

This has the semantics you want. Note that I'm using List instead of Seq, since Scalaz 7 no longer provides the necessary Traverse instance for Seq (although you could easily write your own).


As you've noticed, the following won't compile:

List(Some(1), Some(45)).sequence

Although it's fine if you throw a None in there:

scala> List(Some(1), None, Some(45)).sequence
res0: Option[List[Int]] = None

This is because the inferred type of List(Some(1), Some(45)) will be List[Some[Int]], and we don't have an Applicative instance for Some.

Scalaz provides a handy some method that works like Some.apply but gives you something that's already typed as an Option, so you can write the following:

scala> List(some(1), some(45)).sequence
res1: Option[List[Int]] = Some(List(1, 45))

No extra typing necessary.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • In REPL with Scalaz 7 it fails because it can't find a Traverse typeclass instance for Seq. Maybe there's something else I should import? – Nikita Volkov Sep 10 '12 at 20:35
  • You can use `List` instead of `Seq`, or provide your own instance for `Seq`—I'm not sure why the `Seq` instances have disappeared in 7. – Travis Brown Sep 10 '12 at 21:02
  • Thanks, got it working! But I'm frustrated with its behaviour: besides the `Seq` issue there's another one requiring you to specify the type explicitly: `val xs = List(Some(1), Some(45)); (xs : List[Option[Int]]).sequence` – Nikita Volkov Sep 10 '12 at 21:07