5

私は次のモナドトランスフォーマーを持っています:

newtype Pdf' m a = Pdf' {
  unPdf' :: StateT St (Iteratee ByteString m) a
  }
type Pdf m = ErrorT String (Pdf' m)

基本的には、 Iterateepdf ドキュメントを読み取って処理する基盤を使用します (ドキュメントを常にメモリに保持しないように、ランダム アクセス ソースが必要です)。

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 ()

より良い解決策はありますか?

4

2 に答える 2

0

私がこれまでに見つけた解決策は、コルーチンの 例です。

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

コールバックと同じ動作をしますが、呼び出し元は出力生成を完全に制御できます。

于 2012-06-21T08:44:08.587 に答える
0

これを 1 回のパスで作成するには、間接オブジェクトが書き込まれた場所 (おそらく状態) を保存する必要があります。そのため、保存は動作中に絶対バイト位置を追跡する必要があります.Pdfモナドがこのタスクに適しているかどうかは考慮していません. 最後に到達すると、状態に保存されているアドレスを使用して xref セクションを作成できます。

2 パス アルゴリズムが役立つとは思いません。

6月6日編集:おそらく、あなたの欲求をよりよく理解できます。HTML などのドキュメントを非常に高速に生成するために、名前に「blaze」が含まれるいくつかのライブラリがhackageにあります。手法は、ByteString で 'mconcat' を使用することを避け、中間の 'builder' タイプで使用することです。このためのコア ライブラリは、「blaze-html」および「blaze-textual」で使用される「blaze-builder」のようです。

于 2012-06-03T22:39:47.970 に答える