How to convert A[B[C]] to B[A[C]] if A and B are monads?
Asked Answered
N

1

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.

Neuropathy answered 10/9, 2012 at 20:5 Comment(0)
L
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.

Laurielaurier answered 10/9, 2012 at 20:25 Comment(3)
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?Neuropathy
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.Laurielaurier
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]]).sequenceNeuropathy

© 2022 - 2024 — McMap. All rights reserved.