Государственный переход с государством - PullRequest
0 голосов
/ 05 июня 2018

Я пытаюсь спроектировать переход состояния, используя монаду 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))
}

Это работает, но есть некоторые вещи, которые мешают мне здесь в этом примере.

  1. Могу ли я использовать ReaderWriterStateT и заменить параметры по имени на определенный читатель.Возможно ли это?

  2. Можно ли добавить сюда IO семантику, чтобы приостановить побочные эффекты, которые обеспечивает channel?

...