用于Scala中的理解、尝试和序列
假设你有很多方法:用于Scala中的理解、尝试和序列,scala,for-comprehension,Scala,For Comprehension,假设你有很多方法: def foo() : Try[Seq[String]] def bar(s:String) : Try[String] 你想做一个全面的分析: for { list <- foo item <- list result <- bar(item) } yield result 用于{ 列表一次尝试可以转换为一个选项,你可以用它来理解 scala> def testIt() = { | val dividend = Try(
def foo() : Try[Seq[String]]
def bar(s:String) : Try[String]
你想做一个全面的分析:
for {
list <- foo
item <- list
result <- bar(item)
} yield result
用于{
列表一次尝试可以转换为一个选项,你可以用它来理解
scala> def testIt() = {
| val dividend = Try(Console.readLine("Enter an Int that you'd like to divide:\n").toInt)
| dividend.toOption
| }
testIt: ()Option[Int]
scala> for (x <- testIt()) println (x * x)
Enter an Int that you'd like to divide:
scala> for (x <- testIt()) println (x * x)
Enter an Int that you'd like to divide:
1522756
scala>def testIt()={
|val divident=Try(Console.readLine(“输入要除以的整数:\n”).toInt)
|股息期权
| }
testIt:()选项[Int]
scala>for(x您可以利用这样一个事实,即Try
可以转换为Option
,而Option
可以转换为Seq
:
for {
list <- foo.toOption.toSeq // toSeq needed here, as otherwise Option.flatMap will be used, rather than Seq.flatMap
item <- list
result <- bar(item).toOption // toSeq not needed here (but allowed), as it is implicitly converted
} yield result
如果你想以不同的方式混合你的Try
s和Seq
s,事情会变得更加烦躁,因为没有自然的方法来平复Try[Seq[Try[String]]]
@Yury的答案说明了你必须做的事情
或者,如果您只对代码的副作用感兴趣,您可以:
for {
list <- foo
item <- list
result <- bar(item)
} result
用于{
listIMHO: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)
在您可以使用以进行理解之后(只需导入您的库):
Try可以在中用于理解。但不能与SeqLike混合使用。问题在于,将存在类型未匹配,因为它需要Try[…]并将找到SeqLike。“警告:类DeprecatedConsole中的方法readLine已被弃用:使用scala.io.StdIn中的方法”还可以看到,问题是我将丢失异常详细信息。我希望实现的是处理Seq中的所有元素,如果有元素将抛出异常,则停止。此外,感谢Option的想法。这是一个很好的技巧。我更新了一些关于保留异常详细信息的选项的讨论。我有一种直觉与某种单子魔法有关。我需要花一些时间学习这些东西。似乎真的很有用。完美的答案。唯一的建议是将“序列”方法移动到伴星对象
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)