[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
> import Control.Monad.Writer
> 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.
More information about the Beginners
mailing list