[Haskell-beginners] Q) Using Data.Binary to parse a packet

Brent Yorgey byorgey at seas.upenn.edu
Wed Jul 29 00:26:32 EDT 2009


On Wed, Jul 29, 2009 at 09:19:39AM +0900, Yang, Chul-Woong wrote:
> 
> data Packet = Packet {
> foo :: Word16,
> bar :: Word16,
> baz :: Word32
> } deriving (Show, Eq)
> 
> instance Binary Packet where
> get = do
> foo <- get :: Get Word16
> bar <- get :: Get Word16
> baz <- get :: Get Word32
> return (Packet foo bar baz)
> -- omitting put because we're now just receiving only

By the way, I have nothing to contribute towards solving your actual
problem, but I wanted to point out that you can write this Binary
instance much more simply.  First of all, you can just write

> instance Binary Packet where
>   get = do
>     foo <- get
>     bar <- get
>     baz <- get
>     return (Packet foo bar baz)

and through the magic of type inference, Haskell will figure out the
right instances to use based on the fact that you use foo, bar, and
baz as arguments to Packet, which expects certain types.  (Although
having the type signatures there as documentation is not a terrible
idea.)

But actually, we can do even better:

> import Control.Applicative
>
> instance Binary Packet where
>   get = Packet <$> get <*> get <*> get

Amazing! =) This is exactly the sort of thing Applicative is for.  It
lets us program in an "applicative" style where we apply functions to
arguments, where the arguments are computed in some sort of context
that may have "effects".  Monads give us the power to decide which
monadic actions to run next based on the results of a previous action,
but we don't need that power here: we are always going to run 'get'
three times and put the results in a Packet.  Using Applicative lets
us avoid giving names to the results of the calls to get.

-Brent


More information about the Beginners mailing list