1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
{-|
A pseudo derivation. For each field in the data type, deriving
@LazySet@ generates a function like a record updator, but lazy where possible.
This is very useful in certain situations to improve laziness
properties. A setter is only lazy if that field is present in one constructor.
-}
module Data.Derive.LazySet(makeLazySet) where
{-
test :: Computer
setSpeed :: Int -> Computer -> Computer
setSpeed v x = x{speed=v}
setWeight :: Double -> Computer -> Computer
setWeight v x = Laptop v (speed x)
test :: Sample
-}
import Language.Haskell
import Data.Derive.Internal.Derivation
makeLazySet :: Derivation
makeLazySet = derivationCustom "LazySet" $ \(_,d) -> Right $ concatMap (makeLazySetField d) $ dataDeclFields d
makeLazySetField :: DataDecl -> String -> [Decl]
makeLazySetField d field = [TypeSig sl [name fun] typ, bind fun [pVar "v",pVar "x"] bod]
where
fun = "set" ++ title field
typ = t `TyFun` (dataDeclType d `TyFun` dataDeclType d)
(t,c):tc = [(fromBangType t,c) | c <- dataDeclCtors d, (n,t) <- ctorDeclFields c, n == field]
bod | null tc = apps (con $ ctorDeclName c) [n == field ? var "v" $ Paren $ App (var n) (var "x") | (n,t) <- ctorDeclFields c]
| otherwise = RecUpdate (var "x") [FieldUpdate (qname field) (var "v")]
|