Scala 以非阻塞和懒惰的方式构建一个具有未来的懒散列表
我正在为Clojure频道构建一个Scala facade,该频道提供大量数据,我希望将其表示为一个Scala 以非阻塞和懒惰的方式构建一个具有未来的懒散列表,scala,nonblocking,Scala,Nonblocking,我正在为Clojure频道构建一个Scala facade,该频道提供大量数据,我希望将其表示为一个LazyList[Future[Orther[String,Int]]],左侧可以保存错误消息和右侧数据。从通道中检索每个块是一个阻塞操作,因此我希望在将来封装每个块 每个区块结果类型决定了我们应该如何继续构建惰性列表: null:通道上没有更多结果,返回列表 字符串:添加左侧(错误)并返回列表 Int:addRight(data)并为下一个块递归 我的问题是,我们是否可以以一种懒惰和非阻塞的方式
LazyList[Future[Orther[String,Int]]]
,左侧可以保存错误消息和右侧数据。从通道中检索每个块是一个阻塞操作,因此我希望在将来封装每个块
每个区块结果类型决定了我们应该如何继续构建惰性列表:
左侧(错误)
并返回列表Right(data)
并为下一个块递归//Clojure“通道”虚拟
案例类频道(vs:Any*){
private val it=vs.toIterable.iterator
//相当于'LazyList.empty[Future[or[String,Int]]]]//没有更多值
大小写错误:String=>Future(左(错误))#:::LazyList.empty[Future[other[String,Int]]
案例数据:Int=>Future(右(数据))#::lazyList(频道)
}
等待结果(ll,Duration.Inf)
}
val ll=lazyList(通道(0,1,“错误”))
//正在检索值:0
ll(0)
//(没有输出,因为值0已被计算和记忆)
法律专业(1)
//检索值:1
法律专业(2)
//检索值:错误
我想看到的是:
val ll2=lazyList2(通道(0,1,“错误”))
//(不计算)
ll2(0)
//正在检索值:0
法律责任2(1)
//检索值:1
ll2(2)
//检索值:错误
如果您使用的是fs2,您可以从该频道构建流。给定函数
def nextChunk: Future[A] = ???
您可以使用
val myStream: Stream[IO, A] = Stream.eval(IO.fromFuture(IO(nextChunk))).repeat
在您的特定示例中,您的A
是Any
,您知道在运行时是Int
、String
或null
。您可以首先将它提升到一个选项[String,Int]]
中
def typedChunk(channel: Channel): IO[Option[Either[String, Int]]] =
IO.fromFuture(IO(channel.nextChunk)).map {
case null => None
case s: String => Some(Left(s))
case i: Int => Some(Right(i))
}
def myTerminatedStream(channel: Channel): Stream[IO, Either[String, Int]] =
Stream.eval(typedChunk(channel)).repeat.unNoneTerminate
然后您可以构建流,终止于None
with
def typedChunk(channel: Channel): IO[Option[Either[String, Int]]] =
IO.fromFuture(IO(channel.nextChunk)).map {
case null => None
case s: String => Some(Left(s))
case i: Int => Some(Right(i))
}
def myTerminatedStream(channel: Channel): Stream[IO, Either[String, Int]] =
Stream.eval(typedChunk(channel)).repeat.unNoneTerminate
这就完成了所有保持引用透明性的艰苦工作,并确保它具有正确的评估语义
您请求的LazyList语义将很棘手:只有在Future完成评估后,您才会知道您的区块是空的,因此您需要评估Future以了解列表是否为空。LazyList能够做到这一点,但只能通过阻塞操作实现,而不是从未来实现。您是否考虑过fs2是一种流媒体解决方案,而不是构建自己的解决方案?它经过精心设计,能够有效、正确地解决由类似未来的事物生成的数据流的问题。你不能让一个
LazyList[a]
具有由未来生成的值且不阻塞。当您想要生成下一个A并且有一个未来生成A时,您必须阻塞以等待它。您的阻塞实现将按照您希望在scala 2.13.4中看到的那样工作,它修复了对#::
的急切评估,谢谢,@Martijn。都是懒洋洋地建造的,太棒了。需要进一步探索fs2,看看我将如何将其用于我的外观。当我有了一个例子并运行起来供将来参考时,我会回来的。