Tengo el siguiente transformador mónada:salida perezoso de la acción monádico
newtype Pdf' m a = Pdf' {
unPdf' :: StateT St (Iteratee ByteString m) a
}
type Pdf m = ErrorT String (Pdf' m)
Básicamente, se utiliza subyacente Iteratee
que lee y procesa el documento pdf (requiere fuente de acceso aleatorio, por lo que no va a mantener el documento en memoria todo el tiempo).
Necesito implementar una función que guardará el documento pdf, y quiero que sea flojo, debería ser posible guardar el documento en la memoria constante.
puedo producir perezoso 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
Pero salida real puede depender de salida anterior. (Detalles:.. El documento PDF contiene la llamada "tabla de referencia" con absoluta desplazamiento en bytes de cada objeto dentro del documento Definitivamente depende de la duración de ByteString
objeto PDF es serializado a)
¿Cómo garantizar que la función save
no lo hará fuerza todo ByteString
antes de devolverlo a la persona que llama?
¿Es mejor tomar la devolución de llamada como argumento y llamarla cada vez que tengo algo que mostrar?
import Data.ByteString (ByteString)
save :: Monad m => (ByteString -> Pdf m()) -> Pdf m()
¿Hay alguna solución mejor?
Acabo de agregar una "implementación" para la función 'save' para aclarar el problema. Sí, debería ser un algoritmo de 1 paso, pero no es un problema. El problema en sí: cuando llamo a 'mconcat' para producir el último perezoso' ByteString', ya lo tengo en la memoria. Suponiendo un archivo pdf muy grande, no tengo suficiente memoria para eso. Quiero almacenar solo desplazamientos, no el 'ByteString' en sí. Parece que el enfoque de devolución de llamada resuelve el problema, pero creo que debería existir una mejor solución. – Yuras
Extraño, pero no recibí ninguna notificación sobre su edición el 6 de junio. ¿Cómo '' blaze-builder' puede ayudarme? 'Bulder' es definitivamente más rápido que' ByteString' cuando quieres 'mappend', pero el problema es el uso de la memoria, no el rendimiento. 'str1',' str2', etc. ya estará en la memoria (forzado por BS.length) antes de 'mconcat'. – Yuras