在组成两个defs后展平类型

Vik*_*dya 6 scala scalaz

以下是一个玩具示例,以展示现实生活遗留方法的形状怪异和问题的要点.

正如您所看到的anotherFunc,在将personListexpands类型映射到\/[Throwable,List[\/[Throwable,String]]]不是返回类型但是maping的效果之后personList.再次下面的内容anotherFunc是为了演示目的(实际上有更多有意义的事情发生而不是Option("fakeString")或任何一个.

要求是map personList,如果它right然后对List[Person]返回的每个元素right(从析取返回的一侧)做一些事情.

如何简化/展平返回类型anotherFunc(返回\/[Throwable,List[String]]).可能正在使用其他组合器?

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

    }

  }
}
Run Code Online (Sandbox Code Playgroud)

Tra*_*own 8

诺亚的回答基本上是正确的,但是你应该总是使用traverse而不是a map后跟一个sequence- 两个是等价的,但前者更清晰,效率更高:

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
  }
}
Run Code Online (Sandbox Code Playgroud)

不过,我这是一个答案,而不是评论,因为还有另一种方法可以解决这种在某些情况下更优雅的问题.如果您正在使用ListT析取列表进行大量工作,则可以使用monad转换器使其看起来像是在处理单个级别:

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]
}
Run Code Online (Sandbox Code Playgroud)

现在只需使用anotherFunc.run最终得到一个Throwable \/ List[Person],这完全等同于您当前的代码(但更简洁).


Noa*_*oah 5

如果你flatMappersonList,然后sequenceU向内部列表可以基本flatten的返回类型:

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

Intellij用一些红线抱怨这个但是它正确地为我编译并打印出来\/-(List(fakeString)).

在我看来,这个版本看起来更漂亮一些:

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