Difference between revisions of "Binary IO"

From HaskellWiki
Jump to navigation Jump to search
(link fix)
(style)
Line 1: Line 1:
 
There are a number of binary I/O libraries available for Haskell.
 
There are a number of binary I/O libraries available for Haskell.
   
* JeremyShaw's update of HalDaume's NewBinary package (Cabalized): http://www.n-heptane.com/nhlab/repos/NewBinary
+
* JeremyShaw's update of HalDaume's NewBinary package (Cabalized): http://www.n-heptane.com/nhlab/repos/NewBinary
* [http://www.cse.unsw.edu.au/~dons/fps.html Data.ByteString] (Cabalised) also provides byte level operations, and is used in some applications for binary IO
+
* [http://www.cse.unsw.edu.au/~dons/fps.html Data.ByteString] (Cabalised) also provides byte level operations, and is used in some applications for binary IO
* [http://www.cs.helsinki.fi/u/ekarttun/SerTH/ SerTH], the TH version (sort of) of NewBinary.
+
* [http://www.cs.helsinki.fi/u/ekarttun/SerTH/ SerTH], the TH version (sort of) of NewBinary.
* PeterSimons's BlockIO package (Cabalized): http://cryp.to/blockio/
+
* PeterSimons's BlockIO package (Cabalized): http://cryp.to/blockio/
* JohnGoerzen's MissingH package (Cabalized): http://quux.org/devel/missingh
+
* JohnGoerzen's MissingH package (Cabalized): http://quux.org/devel/missingh
* SimonMarlow's experimental NewIO package: http://www.haskell.org/~simonmar/new-io.tar.gz (documentation at http://www.haskell.org/~simonmar/io/)
+
* SimonMarlow's experimental NewIO package: http://www.haskell.org/~simonmar/new-io.tar.gz (documentation at http://www.haskell.org/~simonmar/io/)
   
  +
For very simple serialisation, use <hask>read</hask> and <hask>show</hask>.
If you have simple binary IO requirements, then FPS might be easiest -- you get a List-like interface to packed byte arrays (interface documented [http://www.cse.unsw.edu.au/~dons/fps/Data.FastPackedString.html here]). For more complex serialisation, NewBinary would be preferred. [[Lambdabot]] follows this rule: when serialising lists and maps, it uses Data.ByteStrings. For complex algebraic datatypes, NewBinary is used (see [http://www.cse.unsw.edu.au/~dons/code/lambdabot/Plugin/Seen.hs Plugin/Seen.hs] in Lambdabot).
 
  +
 
If you have simple binary IO requirements, then Data.ByteString might be easiest -- you get a List-like interface to packed byte arrays (interface documented [http://www.cse.unsw.edu.au/~dons/fps/Data.FastPackedString.html here]). For more complex serialisation, NewBinary would be preferred. [[Lambdabot]] follows this rule: when serialising lists and maps, it uses Data.ByteStrings. For complex algebraic datatypes, NewBinary is used (see [http://www.cse.unsw.edu.au/~dons/code/lambdabot/Plugin/Seen.hs Plugin/Seen.hs] in Lambdabot).
   
 
NewBinary is based on Binary.hs from GHC, and traces back to NHC's binary library, described in [ftp://ftp.cs.york.ac.uk/pub/malcolm/ismm98.html "The Bits Between The Lambdas"]. It is simple to use: for each value you wish to serialise/unserialise, you write an instance of Binary for its type. This can be automated with the DrIFT tool, which will derive binary for you (as is done in GHC's .hi files). You can rip out your own copy of Binary.hs from NewBinary -- just take Binary.hs and FastMutInt.lhs.
 
NewBinary is based on Binary.hs from GHC, and traces back to NHC's binary library, described in [ftp://ftp.cs.york.ac.uk/pub/malcolm/ismm98.html "The Bits Between The Lambdas"]. It is simple to use: for each value you wish to serialise/unserialise, you write an instance of Binary for its type. This can be automated with the DrIFT tool, which will derive binary for you (as is done in GHC's .hi files). You can rip out your own copy of Binary.hs from NewBinary -- just take Binary.hs and FastMutInt.lhs.
   
Lamdabot, hmp3 and hs-plugins are applications I've written using NewBinary, and have found it simple and effective. Here, for example, is the binary serialisation code for the [http://www.cse.unsw.edu.au/~dons/code/hmp3.html hmp3] database type, an Array, and a user defined type: File. Easy!
+
Lamdabot, hmp3 and hs-plugins are applications written using NewBinary, and it fairly simple and effective. Here, for example, is the binary serialisation code for the [http://www.cse.unsw.edu.au/~dons/code/hmp3.html hmp3] database type, an Array, and a user defined type: File. Easy!
   
 
<haskell>
 
<haskell>
instance Binary a => Binary (Array Int a) where
+
instance Binary a => Binary (Array Int a) where
put_ bh arr = do
+
put_ bh arr = do
put_ bh (bounds arr)
+
put_ bh (bounds arr)
mapM_ (put_ bh) (elems arr)
+
mapM_ (put_ bh) (elems arr)
get bh = do
+
get bh = do
((x,y) :: (Int,Int)) <- get bh
+
((x,y) :: (Int,Int)) <- get bh
(els :: [a]) <- sequence $ take (y+1) $ repeat (get bh)
+
(els :: [a]) <- sequence $ take (y+1) $ repeat (get bh)
return $! listArray (x,y) els
+
return $! listArray (x,y) els
   
instance Binary File where
+
instance Binary File where
put_ bh (File nm i) = do
+
put_ bh (File nm i) = do
put_ bh nm
+
put_ bh nm
put_ bh i
+
put_ bh i
get bh = do
+
get bh = do
nm <- get bh
+
nm <- get bh
i <- get bh
+
i <- get bh
return (File nm i)
+
return (File nm i)
 
</haskell>
 
</haskell>
   

Revision as of 01:49, 19 November 2006

There are a number of binary I/O libraries available for Haskell.

For very simple serialisation, use read and show.

If you have simple binary IO requirements, then Data.ByteString might be easiest -- you get a List-like interface to packed byte arrays (interface documented here). For more complex serialisation, NewBinary would be preferred. Lambdabot follows this rule: when serialising lists and maps, it uses Data.ByteStrings. For complex algebraic datatypes, NewBinary is used (see Plugin/Seen.hs in Lambdabot).

NewBinary is based on Binary.hs from GHC, and traces back to NHC's binary library, described in "The Bits Between The Lambdas". It is simple to use: for each value you wish to serialise/unserialise, you write an instance of Binary for its type. This can be automated with the DrIFT tool, which will derive binary for you (as is done in GHC's .hi files). You can rip out your own copy of Binary.hs from NewBinary -- just take Binary.hs and FastMutInt.lhs.

Lamdabot, hmp3 and hs-plugins are applications written using NewBinary, and it fairly simple and effective. Here, for example, is the binary serialisation code for the hmp3 database type, an Array, and a user defined type: File. Easy!

instance Binary a => Binary (Array Int a) where
    put_ bh arr = do
        put_ bh (bounds arr)
        mapM_ (put_ bh) (elems arr)
    get bh      = do
        ((x,y) :: (Int,Int)) <- get bh
        (els   :: [a])       <- sequence $ take (y+1) $ repeat (get bh)
        return $! listArray (x,y) els

instance Binary File where
    put_ bh (File nm i) = do
        put_ bh nm
        put_ bh i
    get bh = do
        nm <- get bh
        i  <- get bh
        return (File nm i)

As an aside, SerTH lets you derive instance of a Binary-alike class automagically using TH, rather than requiring hand-written instances, or DrIFT.

So, in summary. There are a number of ways to do binary IO in Haskell, efficiently and simply. It's really not that hard at all.