Field labels that do updates

Bas van Dijk v.dijk.bas at gmail.com
Wed Mar 4 02:59:41 EST 2009


2009/2/27 Ramin Honary <ramin.honary at gmail.com>:
> I have written a couple of small, experimental virtual machines in Haskell,
> and I always use the State monad with the virtual machine data type as the
> state.
>    data VM a = VM { getAlpha :: Int , getBeta :: String , getGamma :: a }
> which is all well and good, but I inevitably end up writing code like this
> along with it:
>     putAlpha a (VM _ b c) = (VM a b c)
>     putBeta  b (VM a _ c) = (VM a b c)
>     putGamma  c (VM a b _) = (VM a b c)
> Its useful because you can just create one monadic function that updates the
> state and pass one of the "put" functions as a parameter.
>     updateVM :: (x -> VM a -> VM b) -> x -> State (VM b) ()
>     updateVM  putFunc value = do { state <- get ; put (putFunc value state)
> }
>
> ...some algorithm...
>     do updateVM putAlpha 12
>        updateVM putBeta "Hello"
>        return somthing
>
> But writing the "put" functions become tedious for virtual machines with
> more fields in their type, especially if you need to add a field to the data
> type in the future. Could there be syntactic sugar added to generate a list
> of functions that update the fields of a data type?
>    data VM a = VM { getAlpha/putAlpha :: Int , getBeta/putBeta :: String ,
> getGamma/putGamma :: a }
> Where the slash operator is optional, but if included in the code will cause
> the compiler to generate functions of the given names that update those
> fields.
>
> Pros: one more time-saving feature implemented in syntactic sugar. The
> optional nature of the slash operator would give users a choice of whether
> or not to use it.
> Cons: increases complexity of the syntax
>
> I couldn't find such a suggestion on the mailing list, but something tells
> me this idea is too simple to have not been suggested before. Sorry if this
> is a redundant feature request.


With "updates using field labels"
(http://haskell.org/onlinereport/exps.html#record-update) you can
write your put* functions as:

putAlpha a vm = vm {getAlpha = a}
putBeta  b vm = vm {getBeta  = b}
putGamma c vm = vm {getGamma = c}

which make them more resilient against changes in the VM datatype.
However you still have to write them.

There's also a package from Henning Thielemann called "data-accessor"
on hackage (http://hackage.haskell.org/cgi-bin/hackage-scripts/package/data-accessor)
that tries to solve this exact problem. I haven't used it myself so I
can't say it will solve all your problems. Maybe Henning can clarify.

regards,

Bas


More information about the Haskell-prime mailing list