用于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:TrySeq超出了定义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)