是什么让 Bytestring 变得“懒惰”?

lan*_*ula 6 haskell lazy-evaluation bytestring

我正在学习 Haskell,但在理解惰性 ByteStrings 的工作原理时遇到了一些困难。Hackage说“Lazy ByteStrings 使用严格块的惰性列表,这使其适用于 I/O 流任务”。相比之下,严格列表存储为一个大数组。

惰性字节串中的这些“块”是什么?你的编译器如何知道一个块应该有多大?此外,我知道惰性列表背后的想法是您不必存储整个事物,因此允许无限列表和所有这些。但是这个存储是如何实现的呢?每个块都有指向下一个块的指针吗?

非常感谢您的帮助:)

Car*_*ten 8

你可以ByteString这里找到懒惰定义

data ByteString = Empty | Chunk {-# UNPACK #-} !S.ByteString ByteString
    deriving (Typeable)
Run Code Online (Sandbox Code Playgroud)

Chunk一个数据构造函数也是如此- 第一部分是严格的 ( !)严格的( S.)ByteString然后更多ChunksEmpty通过第二个递归(懒惰)ByteString部分。

请注意,第二部分没有(!)那里 - 所以这可以是一个GHC thunk(Haskell 中的懒惰的东西),只有在你需要它时才会被强制执行(例如模式匹配)。

这意味着惰性ByteStringEmpty或者你得到一个严格的(如果你愿意,你可以认为它已经加载了)完整字符串的一部分或,带有惰性剩余/rest/tail ByteString

至于取决于生成这个惰性字节串的代码的大小 - 编译器没有考虑到这一点。

你可以看到这个hGetContents

hGetContents = hGetContentsN defaultChunkSize
Run Code Online (Sandbox Code Playgroud)

wheredefaultChunkSize被定义为32 * 1024 - 2 * sizeOf (undefined :: Int)- 所以有点小于32kB

是的,其余的(snd。参数Chunk)可以被视为指向下一个ChunkEmpty(就像普通列表一样)的指针。