Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell dynamic data-type alteration

Tags:

haskell

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?

like image 924
So8res Avatar asked Dec 14 '11 17:12

So8res


2 Answers

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.)

like image 59
ehird Avatar answered Nov 12 '22 05:11

ehird


This is not possible without Template Haskell. You could use data-accessor and data-accessor-template to remove such boiler plate.

like image 34
jmg Avatar answered Nov 12 '22 05:11

jmg