使用 ZIO 提前中止
Abort early in a fold with ZIO
我想为 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
。所以它看起来短路但是它需要的数量太多了。它是 Int
而不是 Option[Int]
。
一个选项是 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))
}
我看不出有什么理由 return Option[Long]
。
根据 @Yuval Itzchakov 的想法和我的评论 Option
是为了表达一个 Exception (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
没有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
。
我想为 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
。所以它看起来短路但是它需要的数量太多了。它是 Int
而不是 Option[Int]
。
一个选项是 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))
}
我看不出有什么理由 return Option[Long]
。
根据 @Yuval Itzchakov 的想法和我的评论 Option
是为了表达一个 Exception (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
没有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
。