通过递归有效生成延迟ByteString
似乎有一些障碍。为了证明这一点,选择的任务是制作一个惰性随机ByteString
。 (随机数生成只是一个有意义的操作,即占位符,可能会引起任何其他递归。)
这是创建固定长度ByteString
的随机惰性n
的两次尝试。他们分配了大量的堆。首先是一些进口:
import qualified Data.ByteString.Lazy as BSL
import Data.Word8
import System.Random
现在使用cons
的函数:
lazyRandomByteString1 :: Int -> StdGen -> BSL.ByteString
lazyRandomByteString1 n g = fst3 $ iter (BSL.empty, n, g) where
fst3 (a, _, _) = a
iter (bs', n', g') =
if n' == 0 then (bs', 0, g')
else iter (w `BSL.cons` bs', n'-1, g'') where
(w, g'') = random g' :: (Word8, StdGen)
同样,只是使用unfoldr
较短,但几乎和上面一样糟糕:
lazyRandomByteString2 :: Int -> StdGen -> BSL.ByteString
lazyRandomByteString2 n g = BSL.unfoldr f (n, g) where
f :: (Int, StdGen) -> (Int, StdGen)
f (n', g') =
if n' == 0 then Nothing
else Just (w, (n'-1, g'')) where
(w, g'') = random g' :: (Word8, StdGen)
在Data.ByteString.Lazy
提供的内容中,所有这些都是通过递归创建ByteStrings
的可用选项。
接下来,转到Data.ByteString.Lazy.Builder
,它是为构建惰性ByteStrings
而构建的,肯定会提高效率:
import Data.ByteString.Lazy.Builder (Builder, toLazyByteString, word8)
lazyRandomByteString3 :: Int -> StdGen -> BSL.ByteString
lazyRandomByteString3 n g = toLazyByteString builder where
builder :: Builder
builder = fst3 $ iter (mempty, n, g) where
fst3 (a, _, _) = a
iter :: (Builder, Int, StdGen) -> (Builder, Int, StdGen)
iter (b, n', g') =
if n' == 0 then (b, 0, g')
else iter (b <> (word8 w), n'-1, g'') where
(w, g'') = random g' :: (Word8, StdGen)
但不是。
Builder
确实应该能够有效地做到这一点,不是吗? lazyRandomByteString3
有什么问题?
源代码位于github上。