2

我想为ZIO添加一个abort-early-in-a-fold的答案。

所以我采用了猫的解决方案:cats solution

def sumEvenNumbers(nums: Stream[Int]): Option[Long] = {
  import cats.implicits._
  nums.foldM(0L) {
    case (acc, c) if c % 2 == 0 => Some(acc + c)
    case _ => None
  }
}

ZIO如何做到这一点?

我得到的最接近的:

  new DefaultRuntime {}
    .unsafeRun(sumEvenNumbers(List(2,4,6,3,5,6)))

  def sumEvenNumbers(nums: Iterable[Int]): ZIO[Any, Nothing, Int] = {
    stream.Stream.fromIterable(nums)
      .run(Sink.fold(0)(s => s % 2 == 0) { (a: Int, b: Int) => (a + b, Chunk.empty)
      })
  }

但这给了我:15而不是12. 所以它似乎短路了,但它需要的数量太多了。它是一个Intnot Option[Int]

4

3 回答 3

2

没有的解决方案zio.stream.Stream

  def sumEvenNumbers(as: Iterable[Int]): UIO[Option[Int]] =
    ZIO
      .foldLeft(as)(0)((s, a) => if (a % 2 == 0) ZIO.succeed(s + a) else ZIO.fail(s))
      .option
  • 使用.foldLeft- 一旦一个数字不是偶数 - 折叠失败。
  • 用于.option将错误通道合并到成功通道到Option.
于 2020-01-14T18:19:34.787 回答
1

一种选择是takeWhile然后fold

import zio._
import zio.stream._

object Foo extends zio.App {
  override def run(args: List[String]): ZIO[zio.ZEnv, Nothing, Int] =
    Stream
      .fromIterable(List(2, 4, 6, 3, 5, 6))
      .takeWhile(_ % 2 == 0)
      .fold(0L)(_ + _)
      // Just to print the output before terminating
      .flatMap(res => zio.console.putStrLn(res.toString) *> ZIO.succeed(0))
}

我看不出有理由返回一个Option[Long].

于 2020-01-14T15:48:07.443 回答
1

有了@Yuval Itzchakov的想法和我的评论,那Option就是表达一个例外None)。

我想出了这个解决方案:

  def sumEvenNumbers(nums: Iterable[Int]): UIO[Option[Int]] = {
    Stream.fromIterable(nums)
      .run(Sink.foldLeftM(0) { (acc: Int, b: Int) =>
        if (b % 2 == 0)
          ZIO.succeed(acc + b)
        else
          ZIO.fail(acc)
      }).fold(
      _ => None, 
      v => Some(v)
    )
  }
  • 使用foldLeftM- 一旦一个数字不是偶数 - 折叠失败。
  • 将结果折叠为Option
于 2020-01-14T16:51:26.450 回答