2012-07-16 19 views
10

Estoy confundido en cuanto a lo que la mónada Put ofrece sobre el uso de Builder directamente, en Data.Binary. Leí la sección Binary Generation de Tratar con datos binarios, y parece suponer que deberías usar Put, pero es bastante corta y no explica por qué.ByteStrings en Haskell: ¿debería usar Put o Builder?

Data.Binary.Put

La mónada de venta. Una mónada para construir de manera eficiente cadenas de bytes perezosas.

type Put = PutM() 

Ponga simplemente levanta el constructor en una mónada del escritor, se aplica a().

Data.Binary.Builder

la construcción eficiente de cadenas de bytes perezosas.


¿Cuál es el punto de una mónada Writer aplicado a ()?

puedo ver que es Put (un tipo de sinónimos a) una mónada mientras que Builder no es, pero yo realmente no entiendo por qué se necesitaría Put.

En mi caso, renderizo una escena en 3D y escribo cada píxel como un 3 bytes, y luego agrego el encabezado del formato PPM al principio (usará PNG más adelante).

Parece que debe crearse una instancia para tipos que se pueden serializar y deserializar desde y hacia datos binarios. Esto no es exactamente lo que estoy haciendo, pero se sentía natural para crear instancias de Binary para mi tipo de color

instance (Binary a) => Binary (Colour a) where 
    put (Colour r g b) = put r >> put g >> put b 
    get = Colour <$> get <*> get <*> get 

Esto hace que sea fácil de put un Colour Word8 en 24 bits. Pero luego también tengo que virar en el encabezado, y no estoy seguro de cómo debería hacerlo.

¿Está Builder oculto entre bastidores o depende? ¿Es la clase Binary solo para (de) serializar datos, o para todos los propósitos de generación binaria?

+0

No es una respuesta, pero es posible que desee examinar el uso de blaze-builder (y amigos) en lugar de binario. –

+0

@TiloWiklund: Lo había visto antes. ¿Qué tiene de diferente? ¿Es más eficiente? – mk12

+0

Entre otras cosas. Hay una buena reseña de uno de los autores aquí: http://lambda-view.blogspot.se/2010/11/blaze-builder-library-faster.html –

Respuesta

10

En primer lugar, tenga en cuenta la diferencia conceptual. Los constructores son para la construcción eficiente de secuencias de bytes, mientras que la mónada PutM es realmente para la serialización. Entonces, la primera pregunta que debe hacerse es si realmente está serializando (para responder, pregúntese si existe una operación opuesta significativa y exacta: la deserialización).

En general, me gustaría ir con Builder para la comodidad que proporciona. Sin embargo, no el Builder del paquete binario, pero de hecho del paquete blaze-builder. Es un monoide y tiene muchos generadores de cuerdas predefinidos. También es muy composable. Finalmente es muy rápido y de hecho puede ser ajustado.

Por último, pero no menos importante si realmente quieres velocidad, comodidad y el código elegante que se desea combinar esto con una de las distintas bibliotecas procesador de flujos de alrededor como conducto, empadronador o tuberías.

9

puedo ver que Put es una mónada mientras que Builder no es, pero yo realmente no entiendo por qué se necesitaría Put.

Para ser precisos, PutM es Monad. Es necesario para su conveniencia y para darle menos oportunidades de errores. Escribir código en estilo monádico o aplicativo suele ser mucho más conveniente que llevar todos los temporales de forma explícita, y con la instalación de tuberías en la instancia Monad, no puede usar accidentalmente el Builder incorrecto en el medio de su función.

Puede hacer todo lo que hace con PutM usando solo Builder, pero generalmente es más difícil escribir el código.

Pero luego también tengo que virar en el encabezado, y no estoy seguro de cómo debería hacerlo.

No conozco el formato PPM, así que no tengo idea de cómo construir el encabezado. Pero después de construirlo, simplemente puede usar putByteString o putLazyByteString para virarlo.

+0

¿Aceptaría que 'Put' solo esté destinado a la serialización y deserialización, y (por ejemplo) renderizar datos en una sola dirección a una imagen binaria (como ByteString) se haría mejor con' Builder' (posiblemente, blaze-builder) como otros han dicho? – mk12

+0

Yo diría que 'put' y' get' son, pero 'Put' y' Get' se pueden usar razonablemente con un alcance más amplio. Sin embargo, la intención principal de [binary] (http://hackage.haskell.org/package/binary) era de hecho (de) serialización de estructuras Haskell, por lo que la interfaz se formó para eso. Por lo tanto, el desarrollador de blaze puede ser la mejor opción (nunca lo he usado, así que no sé qué tan conveniente es usarlo). –

3

no estoy seguro de hasta qué punto esto es cierto, pero mi entendimiento ha sido siempre que la presentación de Put como se ve es en gran parte un abuso de notación do-por lo que se puede escribir código como este:

putThing :: Thing -> Put 
putThing (Thing thing1 thing2) = do 
    putThing1 thing1 
    putThing2 thing2 

No estamos utilizando la "esencia" de Monad (en particular, nunca vinculamos el resultado de nada) pero obtenemos una sintaxis conveniente y limpia para la concatenación. Sin embargo, las ventajas estéticas más de la alternativa puramente monoidal:

putThing :: Thing -> Builder 
putThing (Thing thing1 thing2) = mconcat [ 
    putThing thing1, 
    putThing thing2] 

son bastante mínimo, en mi opinión.

(Tenga en cuenta que Get, por el contrario, genuinamente es una Mónada y se beneficia de ser tan claro).

Cuestiones relacionadas