私は次のモナドトランスフォーマーを持っています:
newtype Pdf' m a = Pdf' {
unPdf' :: StateT St (Iteratee ByteString m) a
}
type Pdf m = ErrorT String (Pdf' m)
基本的には、 Iteratee
pdf ドキュメントを読み取って処理する基盤を使用します (ドキュメントを常にメモリに保持しないように、ランダム アクセス ソースが必要です)。
PDFドキュメントを保存する関数を実装する必要があり、遅延させたいのですが、ドキュメントを一定のメモリに保存できるはずです。
lazy を生成できます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 ()
より良い解決策はありますか?