什么构成了字节串 "lazy"?

What makes a Bytestring "lazy"?

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

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

非常感谢您的帮助:)

您可以找到 definition of the lazy ByteString here:

data ByteString = Empty | Chunk {-# UNPACK #-} !S.ByteString ByteString
    deriving (Typeable)

所以 Chunk 是一个数据构造函数 - 第一部分是严格的 (!) strict (S.) ByteString 然后通过第二个递归(惰性)ByteString 部分更多 ChunksEmpty

请注意,第二部分没有 (!) - 所以这可以是 GHC thunklazy 中的内容 Haskell)只有当你需要它时才会被强制使用(例如模式匹配)。

这意味着惰性 ByteString 要么是 Empty 要么你得到一个严格的部分(你可以认为这是已经 loaded 如果你愿意的话)或完整字符串的 chunk lazy remaining/rest/tail ByteString.

至于大小取决于生成此惰性字节串的代码 - 编译器不会参与其中。

你可以看到 hGetContents:

hGetContents = hGetContentsN defaultChunkSize

其中 defaultChunkSize 被定义为 32 * 1024 - 2 * sizeOf (undefined :: Int) - 所以比 32kB

少一点

是的,restChunk 的参数)可以看作是指向下一个 ChunkEmpty 的指针(就像 普通 列表一样)。