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

Dmitriy Matrosov sgf.dma at gmail.com
Mon Jan 13 17:54:55 UTC 2014

```Hi.

I have the following data type

> import Data.Monoid

> data Graph    = Graph {graphTitle :: String, graphPoints :: [Int]}
>   deriving (Show)
> emptyGraph :: Graph
> emptyGraph    = Graph {graphTitle = "", graphPoints = []}

Then i want to initialize it in Writer monad using (Dual (Endo Graph))
as monoid:

> type GraphM t = WriterT (Dual (Endo Graph)) t
>
> myGraph :: Monad t => GraphM t [Int]
> myGraph        = do
>                   tell (setTitle "ab")
>                   tell (setTitle "ABCD")
>                   tell (modifyPoints (1 :))
>                   tell (modifyPoints (2 :))
>                   return [1, 2]

and then i can use it e.g. like

> getGraph :: Monad t => (GraphM t a) -> t Graph
> getGraph m    = do
>                   g <- execWriterT m
>                   return (appEndo (getDual g) emptyGraph)
>
> printGraph :: IO ()
> printGraph    = getGraph myGraph >>= print

And to make this work i need two functions implemented for each
record of Graph:

get :: Graph -> a
set :: a -> Graph -> Graph

I can define per-record instances of them, like

> setTitle :: String -> Dual (Endo Graph)
> setTitle x    = Dual . Endo \$ \g -> g{graphTitle = x}
>
> modifyPoints :: ([Int] -> [Int]) -> Dual (Endo Graph)
> modifyPoints f = Dual . Endo \$ \g -> let xs = graphPoints g
>                                      in  g{graphPoints = f xs}

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

where r is record name (or smth else referencing particulat record) and x is
value.
```