Smooth types after composing two defs

The following is an example of toys to demonstrate the strange shape and meaning of the question about real life methods.

As you can see anotherFunc , after displaying over personList , the type expands to \/[Throwable,List[\/[Throwable,String]]] , which is not intended for the return type, but the effect is map ing personList . again, what is shown below inside anotherFunc is for demo purpose (actually, more meaningful things happen instead of Option("fakeString") or any of them.

The requirement is a map personList , and if it is right , then do something with each List[Person] element returned from right (the side that was returned from the disjunction).

how to simplify / smooth the return type of anotherFunc (return \/[Throwable,List[String]] ). Can other combinators be used?

 case class Person(name :String) def personList : \/[Throwable,List[Person]] ={ \/.fromTryCatch{ List(Person("John")) } } def anotherFunc : \/[Throwable,List[\/[Throwable,String]]]= { personList.map{ pl => pl.map{p => for{ s <- Option("fakeString").\/>(new Throwable("not found")) } yield s } } } 
+6
source share
2 answers

The answer to Noah is basically right, but you should always use traverse instead of map , followed by sequence - the two are equivalent, but the first is clearer and slightly more efficient:

 def anotherFunc: Throwable \/ List[String] = personList.flatMap { pl => pl.traverseU { p => for { // I assume you're doing something more interesting here... s <- Option("fakeString").\/>(new Throwable("not found")) } yield s } } 

I am doing this answer instead of commenting though, because there is another way to solve this problem, which may be more elegant in some situations. If you work a lot with disjunction lists, you can use the ListT monad transformer to make it look like you are dealing with one level:

 type OrThrowable[A] = Throwable \/ A def personList = ListT[OrThrowable, Person]( \/.fromTryCatch { List(Person("John")) } ) def anotherFunc: ListT[OrThrowable, String] = personList.flatMap { p => Option("fakeString").\/>(new Throwable("not found")).liftM[ListT] } 

Now just use anotherFunc.run at the end to get Throwable \/ List[Person] , and this is exactly equivalent to your current code (but much shorter).

+8
source

If you are flatMap personList and then sequenceU internal list, you can basically return flatten to type:

  def anotherFunc: \/[Throwable, List[String]] = { personList.flatMap( pl => pl.map( p => for { s <- Option("fakeString").\/>(new Throwable("not found")) } yield s ).sequenceU ) } 

Intellij complains about this with a few red lines, but it compiles and prints correctly for me \/-(List(fakeString)) .

This version looks prettier in my opinion:

  def anotherFunc2: \/[Throwable, List[String]] = { for { pl <- personList res <- pl.map(p => Option("fakeString").\/>(new Throwable("not found"))).sequenceU } yield res } 
+5
source

Source: https://habr.com/ru/post/971131/


All Articles