setters-0.1: Data/Setters.hs
{-# LANGUAGE TemplateHaskell #-}
module Data.Setters
(declareSetters,
declareSetters'
)
where
import Data.Char
import Language.Haskell.TH
-- | Declare setters for all fields of given `data' type.
-- For example, for
--
-- > data Record = Record {
-- > ...
-- > someField :: Integer,
-- > ... }
--
-- one will automatically get
--
-- > someField :: Record -> Integer.
--
-- After calling
--
-- > $(declareSetters ''Record)
--
-- one will get
--
-- > setSomeField :: Integer -> Record -> Record.
declareSetters :: Name -> Q [Dec]
declareSetters name = do
(TyConI (DataD _ _ _ cons _)) <- reify name
return $ concatMap (conSetters "") cons
-- | Similar to 'declareSetters', but add data type name to all setters' names.
-- For example, one will get `setRecordSomeField' instead of `setSomeField'.
declareSetters' :: Name -> Q [Dec]
declareSetters' name = do
(TyConI (DataD _ _ _ cons _)) <- reify name
return $ concatMap (conSetters $ nameBase name) cons
conSetters :: String -> Con -> [Dec]
conSetters prefix (RecC _ fields) = map (fieldSetter prefix) fields
conSetters prefix _ = []
capitalize :: String -> String
capitalize [] = []
capitalize (x:xs) = toUpper x: xs
fieldSetter :: String -> (Name, Strict, Type) -> Dec
fieldSetter prefix (name, _, _) =
let name' = mkName $ "set" ++ capitalize prefix ++ (capitalize $ nameBase name)
record = mkName "record"
value = mkName "value"
body = RecUpdE (VarE record) [(name, VarE value)]
clause = Clause [VarP value, VarP record] (NormalB body) []
in FunD name' [clause]