我有下一个单子变压器:
newtype Pdf' m a = Pdf' {
unPdf' :: StateT St (Iteratee ByteString m) a
}
type Pdf m = ErrorT String (Pdf' m)
基本上,它使用 Iteratee
读取和处理pdf文档的底层(需要随机访问源,这样它就不会一直将文档保存在内存中)。
我需要实现一个保存pdf文档的功能,我希望它是懒惰的,应该可以将文档保存在常量内存中。
我可以产生懒惰ByteString
:
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BS
save :: Monad m => Pdf m ByteString
save = do
-- actually it is a loop
str1 <- serializeTheFirstObject
storeOffsetForTheFirstObject (BS.length str1)
str2 <- serializeTheSecondObject
storeOffsetForTheSecondObject (BS.length str2)
...
strn <- serializeTheNthObject
storeOffsetForTheNthObject (BS.length strn)
table <- dumpRefTable
return mconcat [str1, str2, ..., strn] `mappend` table
但实际输出可能取决于先前的输出。(详细信息:pdf 文档包含所谓的“参考表”,其中包含文档内每个对象的绝对偏移量(以字节为单位)。这绝对取决于ByteString
pdf 对象序列化到的长度。)
如何确保该函数在将其返回给调用者之前save
不会强制执行?ByteString
将回调作为参数并在每次我有输出时调用它会更好吗?
import Data.ByteString (ByteString)
save :: Monad m => (ByteString -> Pdf m ()) -> Pdf m ()
有更好的解决方案吗?