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

后端 未结 1 1052
Happy的楠姐
Happy的楠姐 2020-11-27 21:52

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)

相关标签:
1条回答
  • 2020-11-27 22:17

    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.

    0 讨论(0)
提交回复
热议问题