J'ai le transformateur suivant monade:sortie Lazy d'une action monadique
newtype Pdf' m a = Pdf' {
unPdf' :: StateT St (Iteratee ByteString m) a
}
type Pdf m = ErrorT String (Pdf' m)
Fondamentalement, il utilise sous-jacente Iteratee
qui lit et traite le document pdf (nécessite la source d'accès aléatoire, de sorte qu'il ne sera pas conserver le document en mémoire tout le temps).
J'ai besoin d'implémenter une fonction qui sauvera document pdf, et je veux que ce soit paresseux, il devrait être possible d'enregistrer le document en mémoire constante.
Je peux produire ByteString
paresseux:
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
Mais la production réelle peut dépendre de la sortie précédente. (Détails:.. Document PDF contient donc appelé « table de référence » avec décalage absolu en octets de chaque objet à l'intérieur du document Cela dépend vraiment de la durée du ByteString
objet pdf est sérialisé)
Comment assurer cette fonction save
ne sera pas forcer ByteString
avant de le renvoyer à l'appelant?
Est-il préférable de prendre le rappel comme argument et l'appeler à chaque fois que j'ai quelque chose à la sortie?
import Data.ByteString (ByteString)
save :: Monad m => (ByteString -> Pdf m()) -> Pdf m()
Y a-t-il une meilleure solution?
Je viens d'ajouter une implémentation pour la fonction 'save' afin de rendre le problème plus clair. Oui, ce devrait être un algorithme à un passage, mais ce n'est pas un problème. Le problème en lui-même: quand j'appelle 'mconcat' pour produire le dernier ByteString paresseux, je l'ai déjà en mémoire. En supposant un très gros fichier pdf, je n'ai pas assez de mémoire pour cela. Je veux stocker seulement des décalages, pas le 'ByteString' lui-même. On dirait que l'approche de rappel résout le problème, mais je pense qu'une meilleure solution devrait exister. – Yuras
Étrange, mais je n'ai pas reçu de notification au sujet de votre modification au 6 juin. Comment 'blaze-builder' peut m'aider? 'Bulder' est définitivement plus rapide que' ByteString' quand vous voulez 'mappend', mais le problème est l'utilisation de la mémoire, pas la performance. 'str1',' str2', etc. seront déjà en mémoire (forcé par BS.length) avant 'mconcat'. – Yuras