如何阻止Stream评估下一个元素并以功能方式获得累积结果

时间:2014-09-19 03:45:35

标签: scala functional-programming scalaz

我有这个代码,我想让Stream停止迭代并获得累积的结果。基本上,迭代基于errorLimit number

sealed trait Ele

case class FailureEle() extends Ele
case class SuccessEle() extends Ele

type EitherResult = Either[IndexedSeq[Ele], Seq[FailureEle]]

 def parse(process: Process[Task, Ele], errorLimit: Int): EitherResult = {

  val errorAccumulator = new ListBuffer[FailureEle]
  val taskProcess = process.map(t => {
    t match {
      case x: FailureEle => errorAccumulator += x
      case _ => 
    }
    t
  }).takeWhile(_ => !(errorAccumulator.size == errorLimit))

    val voSeq = taskProcess.runLog.run

    if (errorAccumulator.isEmpty) {
      Left(voSeq)
    } else {
      Right(errorAccumulator)
    }

}
val result = Seq(FailureEle(), SuccessEle(), FailureEle(), SuccessEle(), SuccessEle(), FailureEle(), SuccessEle())

val adaptor = new SeqAdaptor[Ele](result)

val process: Process[Task, Ele] = Process
  .repeatEval(Task {adaptor.next()}).takeWhile(t => !t.shouldStop).map(_.get)

parse(process, 1).isRight //no SuccessEle will be iterated
parse(process, 2).isRight //only one SuccessEle will be iterated
parse(process, 3).isRight //the last one SuccessEle will not be iterated

它正在运行,但有几个问题我想重构解析方法以使其更具功能性:

  • ListBuffer是一种必要的方式

  • takeWhile条件没有逻辑来检查当前元素,它仍然使用ListBuffer结果

所以我想知道是否有一种尾递归方式来使用ListBuffer替换命令式方法。

1 个答案:

答案 0 :(得分:0)

scan可能不够好,但有效

     sealed trait Ele
      case class FailureEle(e: Throwable) extends Ele
      case class SuccessEle(r: String) extends Ele

      def parse(p: Process[Task, Ele], error: Int): Process[Task, (Seq[SuccessEle],   Seq[FailureEle])] = {
            p.scan(Seq[SuccessEle]() -> Seq[FailureEle]()) { (r, e) =>
              val (s, f) = r
              e match {
                case fail: FailureEle =>
                  s  -> (f :+ fail)
                case succ: SuccessEle =>
                  (s :+ succ) -> f
              }
            }.dropWhile { case (succ, fail) => fail.size < error }.take(1)
          }

        def test() {
            def randomFail = {
              val nInt =  scala.util.Random.nextInt()
              println("getting" +  nInt)
              if(nInt % 5 == 0 )
                FailureEle(new Exception("fooo"))
              else
                SuccessEle(nInt.toString)
            }
            val infinite = Process.repeatEval(Task.delay(randomFail))
            val r = parse(infinite, 3).runLast.run
            println(r)
}