在Scala中使用理解,尝试和排序 [英] Using for-comprehension, Try and sequences in Scala
问题描述
假设您有很多方法:
def foo() : Try[Seq[String]]
def bar(s:String) : Try[String]
并且您想理解一下:
for {
list <- foo
item <- list
result <- bar(item)
} yield result
当然不会编译,因为在这种情况下Seq不能与Try一起使用.
任何人都有一个不错的解决方案,如何在不将其分成两个for的情况下将其写得干净整洁?
我已经第三次遇到这个语法问题了,以为是时候问这个问题了.
恕我直言: Try 和 Seq 远远超出了定义monad转换器的需要:>
库代码:
case class trySeq[R](run : Try[Seq[R]]) {
def map[B](f : R => B): trySeq[B] = trySeq(run map { _ map f })
def flatMap[B](f : R => trySeq[B]): trySeq[B] = trySeq {
run match {
case Success(s) => sequence(s map f map { _.run }).map { _.flatten }
case Failure(e) => Failure(e)
}
}
def sequence[R](seq : Seq[Try[R]]): Try[Seq[R]] = {
seq match {
case Success(h) :: tail =>
tail.foldLeft(Try(h :: Nil)) {
case (Success(acc), Success(elem)) => Success(elem :: acc)
case (e : Failure[R], _) => e
case (_, Failure(e)) => Failure(e)
}
case Failure(e) :: _ => Failure(e)
case Nil => Try { Nil }
}
}
}
object trySeq {
def withTry[R](run : Seq[R]): trySeq[R] = new trySeq(Try { run })
def withSeq[R](run : Try[R]): trySeq[R] = new trySeq(run map (_ :: Nil))
implicit def toTrySeqT[R](run : Try[Seq[R]]) = trySeq(run)
implicit def fromTrySeqT[R](trySeqT : trySeq[R]) = trySeqT.run
}
,然后您可以使用理解(只需导入您的库):
def foo : Try[Seq[String]] = Try { List("hello", "world") }
def bar(s : String) : Try[String] = Try { s + "! " }
val x = for {
item1 <- trySeq { foo }
item2 <- trySeq { foo }
result <- trySeq.withSeq { bar(item2) }
} yield item1 + result
println(x.run)
它适用于:
def foo() = Try { List("hello", throw new IllegalArgumentException()) }
// x = Failure(java.lang.IllegalArgumentException)
Let's say you've got a bunch of methods:
def foo() : Try[Seq[String]]
def bar(s:String) : Try[String]
and you want to make a for-comprhension:
for {
list <- foo
item <- list
result <- bar(item)
} yield result
of course this won't compile since Seq cannot be used with Try in this context.
Anyone has a nice solution how to write this clean without breaking it into separate two for's?
I've came across this syntax problem for the thirds time and thought that it's about time to ask about this.
IMHO: Try and Seq is more than what you need to define a monad transformer:
Code for library:
case class trySeq[R](run : Try[Seq[R]]) {
def map[B](f : R => B): trySeq[B] = trySeq(run map { _ map f })
def flatMap[B](f : R => trySeq[B]): trySeq[B] = trySeq {
run match {
case Success(s) => sequence(s map f map { _.run }).map { _.flatten }
case Failure(e) => Failure(e)
}
}
def sequence[R](seq : Seq[Try[R]]): Try[Seq[R]] = {
seq match {
case Success(h) :: tail =>
tail.foldLeft(Try(h :: Nil)) {
case (Success(acc), Success(elem)) => Success(elem :: acc)
case (e : Failure[R], _) => e
case (_, Failure(e)) => Failure(e)
}
case Failure(e) :: _ => Failure(e)
case Nil => Try { Nil }
}
}
}
object trySeq {
def withTry[R](run : Seq[R]): trySeq[R] = new trySeq(Try { run })
def withSeq[R](run : Try[R]): trySeq[R] = new trySeq(run map (_ :: Nil))
implicit def toTrySeqT[R](run : Try[Seq[R]]) = trySeq(run)
implicit def fromTrySeqT[R](trySeqT : trySeq[R]) = trySeqT.run
}
and after you can use for-comrehension (just import your library):
def foo : Try[Seq[String]] = Try { List("hello", "world") }
def bar(s : String) : Try[String] = Try { s + "! " }
val x = for {
item1 <- trySeq { foo }
item2 <- trySeq { foo }
result <- trySeq.withSeq { bar(item2) }
} yield item1 + result
println(x.run)
and it works for:
def foo() = Try { List("hello", throw new IllegalArgumentException()) }
// x = Failure(java.lang.IllegalArgumentException)
这篇关于在Scala中使用理解,尝试和排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!