Разработка ссылочно-прозрачной функции для чтения с канала - PullRequest
0 голосов
/ 04 июня 2018

Я пытаюсь придерживаться стиля чистого FP и хочу создать ссылочную прозрачную функцию.

У меня есть java.nio.channels.SeekableByteChannel, который является источником данных.И как только я открываю файл и получаю экземпляр SeekableFileChannel, мне нужно прочитать первые строки файла и использовать эти строки для определения позиции поиска.

Итак, я создал следующую функцию:

object AdjustChannelAndGetStream {

  def apply(ch: SeekableFileChannel)
           (firstChunksToOffset: List[Array[Byte]] => Long): fs2.Stream[Id, Array[Byte]] {
    val offset = //depending on the first bytes read from the file 
                 //get the number of bytes read before
    val newChannel = ch.position(offset)
    //finally wrap newChannel into fs2.Stream
  }
}

Дело в том, что функция выглядит некрасиво.Не приостанавливает побочные эффекты, что затрудняет тестирование (издевательство SeekableByteChannel).

Я склонен обернуть SeekableByteChannel в IO[SeekableByteChannel] (Scalaz / Cats не имеет значения), но я не понимаю, как это может помочь (нам нужны такие же mock из SeekableByteChannel, нотеперь обернуто в IO).

Можете ли вы помочь мне сконструировать эту функцию в стиле чистого FP (или, по крайней мере, сделать ее не такой уродливой)?

1 Ответ

0 голосов
/ 04 июня 2018

Когда вам нужно обернуть нечистый код, большую часть времени (основываясь на моем опыте), он не будет «красивым».Но мы получаем то, что у нас есть только одна точка, которая имеет дело с «грязными вещами», и мы получаем хорошую абстракцию с этого момента.

Нам нужно создать поток, который связанIO эффект.Вместо Stream[Id, SeekableByteChannel] мы на самом деле находимся в Stream[IO, SeekableByteChannel], потому что мы находимся в контексте эффекта IO:

import java.nio.channels.SeekableByteChannel
import cats.effect.IO

object AdjustChannelAndGetStream {
    def apply(ch: SeekableByteChannel)(
        firstChunksToOffset: List[Array[Byte]] => Long)
      : fs2.Stream[IO, SeekableByteChannel] = {
      fs2.Stream.eval {
        IO {
          val offset: Int = ???
          ch.position(offset)
        }
      }
    }
}

Таким образом, мы приостанавливаем побочный эффект, что мы и хотим сделатьэти побочные эффективные вычисления RT и с этого момента применяют преобразования к потоку.

...