将惰性字节字符串转换为严格字节字符串

23

我有一个函数,它接受一个惰性的ByteString,我希望它返回严格的ByteStrings列表(惰性应该转移到输出的列表类型)。

import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
csVals :: L.ByteString -> [B.ByteString]

我希望出于多种原因, 一些词法分析函数 需要严格的ByteString,而我可以保证上面csVal的输出非常小。 如何在不分块的情况下使ByteString变得更加严格?

更新0

我想把一个Lazy ByteString转换成一个包含所有数据的strict ByteString

6
你对 toChunks 有什么问题?从最初的一瞥来看,它似乎保持了惰性。 - Mikhail Glushenkov
@Matt Joiner:也许你应该自己编写一个词法分析器,或者使用DeepSeq强制评估结果。 - wuxb
@Matt Joiner:在同一个包中有一个惰性版本:'Data.ByteString.Lex.Lazy.Double'。 - wuxb
@MikhailGlushenkov:toChunks返回一个严格的ByteStrings列表。我想把它们全部放在一起。 - Matt Joiner
7
这里有一个误解--一个懒惰的字节串本质上就是一系列块(即严格的字节串)。toChunks展示了这种结构。要把列表全部放入一个严格的字节串中,没有比concat . toChunks(或相同的函数)更好的方法了。在许多典型情况下,列表只有一个元素--在这些情况下,concat . toChunks也相对高效。 - sclv
显示剩余3条评论
5个回答

39

1
有线索表明这是在哪个版本中添加的吗?似乎在Haskell平台2012.4(包括ghc 7.4)中没有。 - Emmanuel Touzery

18

就像@sclv在上面的评论中说的那样,惰性字节字符串只是由严格字节字符串列表组成的。有两种方法可以将惰性字节字符串转换为严格字节字符串(来源:Haskell邮件列表关于添加toStrict函数的讨论)-下面是电子邮件线程中的相关代码:

首先,相关的库:

import qualified Data.ByteString               as B
import qualified Data.ByteString.Internal      as BI
import qualified Data.ByteString.Lazy          as BL
import qualified Data.ByteString.Lazy.Internal as BLI
import           Foreign.ForeignPtr
import           Foreign.Ptr

方法一(与@sclv相同):

toStrict1 :: BL.ByteString -> B.ByteString
toStrict1 = B.concat . BL.toChunks

方法二:

toStrict2 :: BL.ByteString -> B.ByteString
toStrict2 BLI.Empty = B.empty
toStrict2 (BLI.Chunk c BLI.Empty) = c
toStrict2 lb = BI.unsafeCreate len $ go lb
  where
    len = BLI.foldlChunks (\l sb -> l + B.length sb) 0 lb

    go  BLI.Empty                   _   = return ()
    go (BLI.Chunk (BI.PS fp s l) r) ptr =
        withForeignPtr fp $ \p -> do
            BI.memcpy ptr (p `plusPtr` s) (fromIntegral l)
            go r (ptr `plusPtr` l)

如果性能是一个问题,我建议查看上面的电子邮件线程。它还有标准基准测试。在这些基准测试中,toStrict2比toStrict1更快。


5
如果所涉及的惰性ByteString大小<=严格ByteString的最大大小:
toStrict = fromMaybe SB.empty . listToMaybe . toChunks

toChunks方法使得每个数据块尽可能大(除了最后一个数据块可能不完整)。

如果你的惰性ByteString比严格ByteString的大小要,那么这是不可能的:这正是惰性ByteString的用途。


2

Data.ByteString.Lazy.Char8现在有toStrict和fromStrict函数。


1
这似乎基本上是ocharles的答案的重复。 - dfeuer

1
你可以使用blaze-builder来从lazy构建严格的ByteString
toStrict :: BL.ByteString -> BS.ByteString
toStrict = toByteString . fromLazyByteString

它必须有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接