我有下一个monad变换器:
newtype Pdf' m a = Pdf' {
unPdf' :: StateT St (Iteratee ByteString m) a
}
type Pdf m = ErrorT String (Pdf' m)
Run Code Online (Sandbox Code Playgroud)
基本上,它使用底层 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
Run Code Online (Sandbox Code Playgroud)
但实际输出可能取决于以前的输出.(详细信息:pdf文档包含所谓的"引用表",文档中每个对象的绝对偏移量都以字节为单位.这绝对取决于ByteStringpdf对象的序列化长度.)
如何确保save函数ByteString在将其返回给调用者之前不会强制执行?
将回调作为参数更好并在每次输出内容时调用它?
import Data.ByteString (ByteString)
save :: Monad m => (ByteString -> Pdf m ()) -> Pdf m ()
Run Code Online (Sandbox Code Playgroud)
有更好的解决方案吗?
到目前为止我找到的解决方案是协程 示例:
proc :: Int -> Coroutine (Yield String) IO ()
proc 0 = return ()
proc i = do
suspend $ Yield "Hello World\n" (proc $ i - 1)
main :: IO ()
main = do
go (proc 10)
where
go cr = do
r <- resume cr
case r of
Right () -> return ()
Left (Yield str cont) -> do
putStr str
go cont
Run Code Online (Sandbox Code Playgroud)
它的工作与回调相同,但调用者可以完全控制输出生成。
| 归档时间: |
|
| 查看次数: |
311 次 |
| 最近记录: |