我尝试使用State
monad设计状态转换。我实际上有一个java.nio.ReadableByteChannel
,我希望用固定大小的块(例如4096字节)读取它,然后组合这些块的一些记录(例如用行)。
为了保持纯FP风格,我定义了类型Chunker:
type Chunker =
(List[Array[Byte]], Array[Byte]) => (List[Array[Byte]], Option[Array[Byte]])
现在使用提供的chunker以递归方式定义状态转换,如下所示:
def takeFirstElement(chunker: Chunker)(chunk: => Option[Array[Byte]]):
State[List[Array[Byte]], Option[Array[Byte]]] =
chunk match {
case None => State.pure(None)
case Some(ba) => scanNextChunk(chunker)(ba) flatMap {
case None => takeFirstElement(chunker)(chunk)
case v @ Some(a) => State.pure(v)
}
}
def scanNextChunk(chunker: Chunker)(chunk: Array[Byte]):
State[List[Array[Byte]], Option[Array[Byte]]] = State(chunker(_, chunk))
现在我为它写了一个简单的测试
def main(args: Array[String]): Unit = {
val chunker: Chunker = //some complicated chunker
val channel = //some channel
val buf = ByteBuffer.allocate(8)
val result = takeFirstElement(chunker) {
val bytesRead = channel.read(buf)
val data = if (bytesRead >= 0) {
val ba = new Array[Byte](bytesRead)
System.arraycopy(buf.array(), 0, ba, 0, bytesRead)
Some(ba)
} else
None
buf.clear()
data
}.run(List.empty)
println(new String(result.value._2.get))
}
它有效,但在这个例子中有些东西困扰我。
我可以使用ReaderWriterStateT
并使用已定义的阅读器替换名称参数。有可能吗?
是否可以在此处添加IO
语义来暂停channel
提供的副作用?