I have some haskell boilerplate that looks something like this:
data Configuration
{ confA :: Integer
, confB :: Boolean
, confC :: String }
x = (\arg opt -> opt{ confA=arg })
y = (\arg opt -> opt{ confB=arg })
z = (\arg opt -> opt{ confC=arg })
and I'd like to remove the boilerplate, yielding something along the lines of:
setter :: (Config -> a) -> a -> Config -> Config
x = setter confA
y = setter confB
z = setter confC
But I have no idea how to construct such a setter
function. Is this even possible in (non-template) haskell or am I butting up against the syntax sugar here? If so, how would I do such a thing in template haskell?
This isn't possible with just Haskell's record system. What you want are lenses; this previous Stack Overflow question and its top answer are a good introduction. Personally, I use the data-lens package talked about there. (See also data-lens-fd to use it with the MonadState class from mtl — if you don't know what that is, just know that you should probably use it whenever you want to use lenses in a State
monad.)
The data-lens-template package might be the application of Template Haskell you want; it derives lens definitions for record fields.
The other popular lens package is fclabels. I prefer data-lens for its simplicity and speed; fclabels (as of version 1.0) is slightly more flexible, but you don't need that flexibility for what you want to do. (Note that due to its newly-increased flexibility, fclabels' (:->)
type can no longer be directly translated to the simple definition of lenses, as mentioned in the Stack Overflow answer I linked.)
This is not possible without Template Haskell. You could use data-accessor and data-accessor-template to remove such boiler plate.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With