什么构成了字节串 "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
部分更多 Chunks
或 Empty
。
请注意,第二部分没有 (!)
- 所以这可以是 GHC thunk(lazy 中的内容 Haskell)只有当你需要它时才会被强制使用(例如模式匹配)。
这意味着惰性 ByteString
要么是 Empty
要么你得到一个严格的部分(你可以认为这是已经 loaded 如果你愿意的话)或完整字符串的 chunk lazy remaining/rest/tail ByteString
.
至于大小取决于生成此惰性字节串的代码 - 编译器不会参与其中。
你可以看到 hGetContents
:
hGetContents = hGetContentsN defaultChunkSize
其中 defaultChunkSize
被定义为 32 * 1024 - 2 * sizeOf (undefined :: Int)
- 所以比 32kB
少一点
是的,rest(Chunk
的参数)可以看作是指向下一个 Chunk
或 Empty
的指针(就像 普通 列表一样)。
我正在学习 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
部分更多 Chunks
或 Empty
。
请注意,第二部分没有 (!)
- 所以这可以是 GHC thunk(lazy 中的内容 Haskell)只有当你需要它时才会被强制使用(例如模式匹配)。
这意味着惰性 ByteString
要么是 Empty
要么你得到一个严格的部分(你可以认为这是已经 loaded 如果你愿意的话)或完整字符串的 chunk lazy remaining/rest/tail ByteString
.
至于大小取决于生成此惰性字节串的代码 - 编译器不会参与其中。
你可以看到 hGetContents
:
hGetContents = hGetContentsN defaultChunkSize
其中 defaultChunkSize
被定义为 32 * 1024 - 2 * sizeOf (undefined :: Int)
- 所以比 32kB
是的,rest(Chunk
的参数)可以看作是指向下一个 Chunk
或 Empty
的指针(就像 普通 列表一样)。