[Haskell-beginners] Initialize a data type in (Writer (Endo a)) monoid

Brent Yorgey byorgey at seas.upenn.edu
Mon Jan 13 19:07:27 UTC 2014

On Mon, Jan 13, 2014 at 09:54:55PM +0400, Dmitriy Matrosov wrote:
> but if Graph has many records, for most of them these 'set' functions ('get'
> functions i'll have from records) will look very similar. Is there a way how i
> can define all of them "in one row", i.e. using some generic 'set'
> implementation to which i should only pass e.g. record name or smth else?
> I.e. so, that above myGraph will look like
>     ..
>     tell(set r x)
>     ..

Yes, you can do this with the 'lens' package.  The package is big and
complicated, but here's all you need to know:

0) import Control.Lens

1) Name your fields with underscores:

> data Graph    = Graph { _graphTitle :: String, _graphPoints :: [Int] }
>   deriving (Show)

2) Add the line

> $(makeLenses ''Graph)

after the definition of Graph (also be sure the TemplateHaskell
extension is enabled)

3) Now you can use the 'view' and 'set' functions (or their infix
equivalents, (^.) and (.~)), like so:

  tell (set graphTitle x)


  tell (graphTitle .~ x)

makeLenses generated a special lens called 'graphTitle' from the field
name '_graphTitle'.

Of course the above doesn't actually typecheck since (set graphTitle x)
is a function but you need a Dual Endo, but you can easily make your
own custom set function that adds the Dual Endo wrapper, etc.


More information about the Beginners mailing list