how to flatten disjunction type
Asked Answered
S

4

6

If I have a following method

 def getMyList :\/[Throwable,List[\/[Throwable,Int]]] ={
 ....
 }

how to flatten type of getMyList to \/[Throwable,List[Int]]

Stoltz answered 22/9, 2014 at 23:36 Comment(0)
U
9

Just flatMap and sequenceU, it's all in scalaz:

  def flatten(e: \/[Throwable,List[\/[Throwable,Int]]]): \/[Throwable,List[Int]] = {
    e.flatMap(a => a.sequenceU)
  }
Understandable answered 23/9, 2014 at 0:9 Comment(6)
Nice answer, could you give a short explanation of sequenceU. I tried with ordinary sequence but failed.Grizzly
@Grizzly sequenceU automatically infers the right type constructor for the Applicative instance. Here's an article worth reading on the subject: eed3si9n.com/learning-scalaz-day15Spiritualism
What @GabrielePetronella said :)Understandable
@GabrielePetronella thanks for the explanation. Coming from Haskell Scala's type inference, is sometimes really annoying.Grizzly
You may also want to take a look at traverseU as a potential alternative to sequenceU in order to get \/[Throwable,List[Int]] earlier on.Spriggs
For clarification of my previous comment, this answer is correct. However, depending on code in getMyList, it may be possible to replace a map across the List and sequenceU with traverseU.Spriggs
N
1

If by flatten, you mean remove the left types from List[\/[Throwable,Int]], then you can map the outer disjunction, and collect the right types:

list.map(_.collect{ case \/-(x) => x})
Neoarsphenamine answered 22/9, 2014 at 23:48 Comment(0)
L
0

I don't think that some higher order "flatten" exists for /. Looks like Validateion & ValidationNEL will be better choice for this problem. However here is "dirty" solution for /, it will return first fail. If you want to accumulate failures Validation is way to go

 val getMyList: \/[Throwable,List[\/[Throwable,Int]]] =
    //\/-(List(-\/(new RuntimeException("test")), \/-(1)))
    \/-(List(\/-(2), \/-(1)))


  val flatten = getMyList.fold(\/.left, _.foldLeft(\/.right[Throwable, List[Int]](List.empty[Int])) {
    case (\/-(list), \/-(i)) => \/-(list :+ i)
    case (\/-(list), -\/(err)) => -\/(err)
    case (-\/(err), _) => -\/(err)
  })

  println(flatten)
Lewes answered 22/9, 2014 at 23:48 Comment(1)
See join in BindSyntax - github.com/scalaz/scalaz/blob/series/7.1.x/core/src/main/scala/…. This provides join which is essentially synonymous with flatten for all types A which have a Bind[A].Spriggs
E
0

We use the following method, where .sSuccess creates a \/[_, Seq[T]] and .sFail creates a \/[Throwable, _] with all of the throwables' error messages concatenated:

implicit class CondenseEither[T](seq: Seq[\/[Throwable,T]]) = {
  def condenseSeq: \/[Throwable, Seq[T]] = {
    val errs = seq.filter(_.isLeft).map(_.toEither)
    if(errs.isEmpty) seq.map(_.toEither).map(_.right.get).sSuccess
    else errs.map(_.left.get.getMessage).mkString(", ")).sFail
  }
}

There's probably a way to do this without the toEithers

Electromagnet answered 22/9, 2014 at 23:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.