Field labels that do updates

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