Field labels that do updates

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.

2009/2/27 Ramin Honary
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
participants (2)
-
Bas van Dijk
-
Ramin Honary