简体   繁体   English

设计参照透明功能以从通道读取

[英]Designing referentially transparent function for reading from channel

I'm trying to adhere to pure-FP style and want to design a referentially transparent function. 我试图坚持纯FP风格,并希望设计一个参照透明功能。

I have a java.nio.channels.SeekableByteChannel , which is a data source. 我有一个java.nio.channels.SeekableByteChannel ,它是一个数据源。 And soon as I open a file and get the SeekableFileChannel instance, I need to read the first lines of the file and use these lines to determine the seek position. 打开文件并获取SeekableFileChannel实例后,我需要读取文件的第一行,并使用这些行确定查找位置。

So I created the following function: 因此,我创建了以下函数:

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
  }
}

The thing is, the function looks ugly. 问题是,该函数看起来很丑。 It does not suspend side effects, which makes it difficult to test (mocking SeekableByteChannel ). 它不会暂停副作用,这使其难以测试(模拟SeekableByteChannel )。

I tend to wrap SeekableByteChannel into IO[SeekableByteChannel] (Scalaz/Cats does not matter), but I don't see how it can help (we need the same mock of SeekableByteChannel , but now wrapped into IO ). 我倾向于将SeekableByteChannel包装到IO[SeekableByteChannel] (Scalaz / Cats无关紧要),但是我看不到它有什么帮助(我们需要相同的SeekableByteChannel mock ,但现在包装到IO )。

Can you help me to design this function in pure-FP style (or at least to make it not so ugly)? 您能否帮助我以纯FP样式设计此功能(或至少使其不那么难看)?

When you need to wrap impure code, most of the time (based on my experience), it's not going to "be pretty". 当您需要包装不纯净的代码时,大多数时候(根据我的经验),它不会变得“漂亮”。 But, what we gain is that we only have a single point which deals with the "messy stuff", and we get a nice abstraction from there on. 但是,我们得到的是,只有一个点可以处理“混乱的东西”,并且从那里可以得到很好的抽象。

What we want is to create a stream which is bound by an IO effect. 我们想要的是创建一个受IO效果约束的流。 Instead of Stream[Id, SeekableByteChannel] , we're really in Stream[IO, SeekableByteChannel] because we are in the IO effect context: 实际上,我们位于Stream[IO, SeekableByteChannel] Stream[Id, SeekableByteChannel]而不是Stream[Id, 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)
        }
      }
    }
}

This way, we suspend the side effect, which is what we want to make these side effectful computation RT, and apply transformations on the stream from this point on. 这样,我们暂停了副作用,这就是我们想要进行这些副作用计算RT的过程,并从此开始对流应用转换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM