在组成两个defs后展平类型

时间:2014-06-21 11:01:55

标签: scala scalaz

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

正如您可以看到anotherFunc,在personList上展开后,将展开类型扩展为\/[Throwable,List[\/[Throwable,String]]],这不是预期的返回类型,而是map ing 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 } } } )。可能正在使用其他组合器?

{{1}}

2 个答案:

答案 0 :(得分:8)

诺亚的回答基本上是正确的,但你应该总是使用traverse而不是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
  }
}

我这是一个答案而不是评论,但是,因为还有另一种方法可以解决这种在某些情况下更优雅的问题。如果您正在使用析取列表进行大量工作,则可以使用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]
}

现在只需使用anotherFunc.run来获得Throwable \/ List[Person],这与您当前的代码完全相同(但更简洁)。

答案 1 :(得分:5)

如果您flatMap personList然后sequenceU内部列表,您基本上可以flatten返回类型:

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

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

在我看来,这个版本看起来有点漂亮:

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