Я пытаюсь спроектировать переход состояния, используя монаду State
.У меня на самом деле есть java.nio.ReadableByteChannel
, и я хочу прочитать его фрагментами фиксированного размера (например, 4096 байт), а затем объединить некоторые записи из этих фрагментов (например, по строкам).
Чтобы остаться в чистом стиле FP, я определил тип Chunker:
type Chunker =
(List[Array[Byte]], Array[Byte]) => (List[Array[Byte]], Option[Array[Byte]])
А теперь рекурсивно определяем переход состояния, используя предоставленный чанкер, следующим образом:
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
?