用ZIO在Scala中组合多重期货和期权

用ZIO在Scala中组合多重期货和期权,scala,functional-programming,scalaz,zio,Scala,Functional Programming,Scalaz,Zio,我刚刚开始评估ZIO,以改进编程模型和异步Scala代码的性能。在我的代码库中,我经常处理Future[Option[T],到目前为止,我已经使用Scalaz的OptionTmonad transformer处理了这个问题。现在我想和齐奥试试这个 考虑两个功能: def foo:String=>Future[Option[T]] 和 def-bar:T=>Future[U] 我试过这样的方法: val t = for { o: Option[Int] <- ZIO.fromF

我刚刚开始评估ZIO,以改进编程模型和异步Scala代码的性能。在我的代码库中,我经常处理
Future[Option[T]
,到目前为止,我已经使用Scalaz的
OptionT
monad transformer处理了这个问题。现在我想和齐奥试试这个

考虑两个功能:

def foo:String=>Future[Option[T]]
def-bar:T=>Future[U]

我试过这样的方法:

val t = for {
       o: Option[Int] <- ZIO.fromFuture { implicit ec =>
            foo("test")
       }
       i: Int <- ZIO.fromOption(o)
       s: String <- ZIO.fromFuture { implicit ec =>
            bar(i)
       }
} yield s
val t=for{
o:选项[Int]
foo(“测试”)
}
i:Int的类型是
IO[Unit,A]
,它是
ZIO[Any,Unit,A]
,而
ZIO.fromFuture的类型是
Task[A]
,它是
ZIO[Any,Throwable,A]
,如所述。因此,类型不对齐

ZIO[Any, Unit, A]
ZIO[Any, Throwable, A]
尝试
maperor
将错误类型与
Throwable
对齐,如下所示

for {
  o <- ZIO.fromFuture { implicit ec => foo("test") }
  i <- ZIO.fromOption(o).mapError(_ => new RuntimeException("boom"))
  s <- ZIO.fromFuture { implicit ec => bar(i)}
} yield s
用于{
o foo(“测试”)}
i新的运行时异常(“boom”))
s bar(i)}
}产量
的类型是
IO[Unit,A]
,它是
ZIO[Any,Unit,A]
,而
ZIO.fromFuture的类型是
Task[A]
,它是
ZIO[Any,Throwable,A]
,如所述。因此,类型不对齐

ZIO[Any, Unit, A]
ZIO[Any, Throwable, A]
尝试
maperor
将错误类型与
Throwable
对齐,如下所示

for {
  o <- ZIO.fromFuture { implicit ec => foo("test") }
  i <- ZIO.fromOption(o).mapError(_ => new RuntimeException("boom"))
  s <- ZIO.fromFuture { implicit ec => bar(i)}
} yield s
用于{
o foo(“测试”)}
i新的运行时异常(“boom”))
s bar(i)}
}产量

在这种情况下,有几个操作符可以帮助您,基本上,我建议使用
some
asSomeError
的组合,而不是使用
fromOption
显式地展开
选项

val t: Task[Option[String]] = (for {

  // This moves the `None` into the error channel
  i: Int <- ZIO.fromFuture(implicit ec => foo("test")).some

  // This wraps the error in a Some() so that the signature matches
  s: String <- ZIO.fromFuture(implicit ec => bar(i)).asSomeError

} yield s).optional // Unwraps the None back into the value channel
val t:Task[选项[字符串]]=(用于{
//这会将“无”移动到错误通道中
i:Int-foo(“测试”)。一些
//这会将错误包装在Some()中,以便签名匹配
s:字符串条(i)).asSomeError
}产量s)。可选//将无重新打开到值通道中

在这种情况下,有几个操作符可以帮助您,基本上,我建议使用
some
asSomeError
的组合,而不是使用
fromOption
显式地展开
选项

val t: Task[Option[String]] = (for {

  // This moves the `None` into the error channel
  i: Int <- ZIO.fromFuture(implicit ec => foo("test")).some

  // This wraps the error in a Some() so that the signature matches
  s: String <- ZIO.fromFuture(implicit ec => bar(i)).asSomeError

} yield s).optional // Unwraps the None back into the value channel
val t:Task[选项[字符串]]=(用于{
//这会将“无”移动到错误通道中
i:Int-foo(“测试”)。一些
//这会将错误包装在Some()中,以便签名匹配
s:字符串条(i)).asSomeError
}产量s)。可选//将无重新打开到值通道中

这看起来更像是一种黑客行为,它引入了一个
异常
(或者更准确地说,是一个
可丢弃的
),其唯一目的是对齐类型以使
理解工作正常。虽然我很欣赏这个答案,但它并不是真的有用。这意味着在理解
之外,还有一种更惯用的方法来处理这种情况。此外,您如何处理
None
案例?您如何处理
foo
bar
中出现“真实”错误的可能性?这不是一种黑客行为-如果您想编写计算,它们的类型必须对齐。在这方面,齐奥与两人都没有太大区别。ZIO中“神奇地”对齐的是输入/环境。其他参数将查找要向上转换的公共类型,这会使您知道它们中的任何一个都是完全不相关的(如Option和Throwable in error param)。是的,引入
RuntimeException
的目的与您描述的完全一样。所谓“hack”,我的意思是
RuntimeException
的存在不是为了增加业务价值,而是为了使编程模型工作。在
mapError
中执行什么操作并不重要,只要调用它即可。那感觉不太好。但是,如果您想用
for
comp解决这个问题,您需要这样做。尽管我关于解析出三种场景的问题在ZIO的v1.x版本中仍然没有答案,但文档已经改进,现在@paulpdaniels的复制
选项[T]
的解决方案完全正确,这是有道理的,因为我们给出的原因这看起来更像是一种黑客行为,它引入了一个
异常
(或者更准确地说,一个
可丢弃的
),其唯一目的是对齐类型,使
用于理解。虽然我很欣赏这个答案,但它并不是真的有用。这意味着在理解
之外,还有一种更惯用的方法来处理这种情况。此外,您如何处理
None
案例?您如何处理
foo
bar
中出现“真实”错误的可能性?这不是一种黑客行为-如果您想编写计算,它们的类型必须对齐。在这方面,齐奥与两人都没有太大区别。ZIO中“神奇地”对齐的是输入/环境。其他参数将查找要向上转换的公共类型,这会使您知道它们中的任何一个都是完全不相关的(如Option和Throwable in error param)。是的,引入
RuntimeException
的目的与您描述的完全一样。所谓“hack”,我的意思是
RuntimeException
的存在不是为了增加业务价值,而是为了使编程模型工作。在
mapError
中执行什么操作并不重要,只要调用它即可。那感觉不太好。但是,如果您想用
for
comp解决这个问题,您需要这样做。尽管我关于解析出三种场景的问题在ZIO的v1.x版本中仍然没有答案,但文档已经改进,现在@paulpdaniels的复制
选项[T]
的解决方案完全正确,这是有道理的,因为我们认为这太棒了。优雅、惯用,似乎非常符合ZIO心智模型,我仍在努力理解它。谢谢如果我有一个函数
任务,那么你的RxJS书在一个相关的注释上是令人惊叹的