Presentation is loading. Please wait.

Presentation is loading. Please wait.

Scrap Your Boilerplate /~simonpj/papers/hmap/

Similar presentations


Presentation on theme: "Scrap Your Boilerplate /~simonpj/papers/hmap/"— Presentation transcript:

1 Scrap Your Boilerplate http://research.microsoft.com /~simonpj/papers/hmap/

2 Outline Boilerplate code Boilerplate code Idea Idea Recursively apply Recursively apply Generic transform Generic transform “ Casting ” solution“ Casting ” solution AOP solutionAOP solution Visitor pattern Visitor pattern Queries and monadic transformations Queries and monadic transformations Boilerplate 2 & 3 Boilerplate 2 & 3

3 Boilerplate Code data Company= C [Dept] data Dept= D Name Manager [SubUnit] data SubUnit= PU Employee | DU Dept data Employee= E Person Salary data Person= P Name Address data Salary= S Float type Manager= Employee type Name= String type Address= String increase :: Float -> Company -> Company increase k (C ds) = C (map (incD k) ds) incD k (D nm mgr us) = D nm (incE k mgr) (map (incU k) us) incU k (PU e) = PU (incE k e) incU k (DU d) = DU (incD k d) incE k (E p s) = E p (incS k s) incS k (S s) = S (s * (1 + k)) Boilerplate

4 Idea Apply a generic transform Apply a generic transform Replacing incD, incU, incE and incSReplacing incD, incU, incE and incS Apply the transform Apply the transform RecursivelyRecursively BlindlyBlindly Only affect the items we want Only affect the items we want Increase k = everywhere $ mkT $ incS k Increase k = everywhere $ mkT $ incS k Generate a generic transform Recursively, blindly apply

5 Recursively apply One-layer traversal One-layer traversal class Typeable a => Term a where gmapT :: (forall b. Term b => b -> b) -> a -> a class Typeable a => Term a where gmapT :: (forall b. Term b => b -> b) -> a -> a instance Term Employee where gmapT f (E per sal) = E (f per) (f sal) instance Term Employee where gmapT f (E per sal) = E (f per) (f sal) instance Term Bool where gmapT f x = x instance Term Bool where gmapT f x = x instance Term a => Term [a] where gmapT f []= [] gmapT f (x:xs)= f x : f xs instance Term a => Term [a] where gmapT f []= [] gmapT f (x:xs)= f x : f xs

6 Recursively apply (cont.) everywhere :: Term a => (forall b. Term b => b -> b) -> a -> a everywhere :: Term a => (forall b. Term b => b -> b) -> a -> a everywhere f x = f $ gmapT (everywhere f) x everywhere f x = f $ gmapT (everywhere f) x everywhere ’ f x = gmapT (everywhere ’ f) (f x) everywhere ’ f x = gmapT (everywhere ’ f) (f x)

7 Recursively apply (cont.) Every involved data type have to be an instance of Term Every involved data type have to be an instance of Term The instantiation can be generated automatically The instantiation can be generated automatically “ deriving ” in GHC 6.4“ deriving ” in GHC 6.4 Different combinations of gmapT lead to different traversal policy Different combinations of gmapT lead to different traversal policy Rank-2 types, signature always needed Rank-2 types, signature always needed

8 “Casting” Solution class Typeable class Typeable cast :: (Typeable a, Typeable b) => a -> Maybe b cast :: (Typeable a, Typeable b) => a -> Maybe b (cast ‘ a ’ ) :: Maybe Char(cast ‘ a ’ ) :: Maybe Char Just ‘ a ’ Just ‘ a ’ (cast ‘ a ’ ) :: Maybe Bool(cast ‘ a ’ ) :: Maybe Bool Nothing Nothing (cast True) :: Maybe Bool(cast True) :: Maybe Bool Just True Just True

9 “Casting” Solution (cont.) mkT: generate a generic transform mkT: generate a generic transform When the applied parameter is what we expect, apply the transformWhen the applied parameter is what we expect, apply the transform Otherwise, work like idOtherwise, work like id mkT :: (Typeable a, Typeable b) => (b -> b) -> a -> a mkT :: (Typeable a, Typeable b) => (b -> b) -> a -> a mkT f = case cast f of Just g-> g Nothing-> id mkT f = case cast f of Just g-> g Nothing-> id

10 “Casting” Solution (cont.) Need a language supported “ cast ” Need a language supported “ cast ” GHC 6.4 internal/libraryGHC 6.4 internal/library Data.Typeable: Typeable, castData.Typeable: Typeable, cast Data.Generics.Basic: Data (Term)Data.Generics.Basic: Data (Term) Cannot write transformation directly, always generated by mkT Cannot write transformation directly, always generated by mkT

11 AOP Solution incS is itself the (dummy) generic transform incS is itself the (dummy) generic transform Decide whether the transform is applied or not by advice Decide whether the transform is applied or not by advice incS :: Float -> a -> a incS k = id incS :: Float -> a -> a incS k = id advice around {incS k} (arg::Salary) = case arg of (S x) -> (S x*(1+k)) advice around {incS k} (arg::Salary) = case arg of (S x) -> (S x*(1+k)) increase k = everywhere $ incS k increase k = everywhere $ incS k

12 AOP Solution (cont.) type Salary = Float type Salary = Float In “ casting ” solution, every field with type Float will be multiplied (including height, weight, etc.) In “ casting ” solution, every field with type Float will be multiplied (including height, weight, etc.) In AOP Solution (?): advice around {incS k} (arg::Salary) = arg * (1 + k) In AOP Solution (?): advice around {incS k} (arg::Salary) = arg * (1 + k)

13 AOP Solution (cont.) Less boilerplate code Less boilerplate code Less data type for distinguishing meaning of data Less data type for distinguishing meaning of data Dummy transformation, real work is done by advices Dummy transformation, real work is done by advices idT = id advice around {idT} (arg::Salary) = incS k arg increase = everywhere idTidT = id advice around {idT} (arg::Salary) = incS k arg increase = everywhere idT

14 Visitor pattern

15 Visitor pattern (cont.) Widely used in single-dispatch OO languages Widely used in single-dispatch OO languages Visited object do the recursion Visited object do the recursion Decide whether the transform is applied or not by dispatching Decide whether the transform is applied or not by dispatching

16 Queries and monadic transform class Typeable a => Term a where gmapT :: (forall b. Term b => b -> b) -> a -> a gmapQ :: (forall b. Term b=> b -> r) -> a -> [r] gmapM :: Monad m => (forall b. Term b -> m a) -> a -> m a -- special cases of gfoldl class Typeable a => Term a where gmapT :: (forall b. Term b => b -> b) -> a -> a gmapQ :: (forall b. Term b=> b -> r) -> a -> [r] gmapM :: Monad m => (forall b. Term b -> m a) -> a -> m a -- special cases of gfoldl everything :: Term a => (r -> r -> r) -> (forall a. Term a => a -> r) -> a -> r everything :: Term a => (r -> r -> r) -> (forall a. Term a => a -> r) -> a -> r everywhereM :: (b -> m b) -> a -> m a everywhereM :: (b -> m b) -> a -> m a

17 Queries and monadic transform (cont.) (r `mkQ` q) a = case cast a of Just b-> q b Nothing-> r (r `mkQ` q) a = case cast a of Just b-> q b Nothing-> r mkM f = case cast f of Just g-> g Nothing-> return mkM f = case cast f of Just g-> g Nothing-> return totalBill = everything (+) (0 `mkQ` billS) totalBill = everything (+) (0 `mkQ` billS) dbSalaries = everywhereM (mkM lookupE) dbSalaries = everywhereM (mkM lookupE)

18 Queries and monadic transform (cont.) queryS _ = 0 :: Float queryS _ = 0 :: Float advice around {queryS} (arg::Salary) = case arg of S s -> s advice around {queryS} (arg::Salary) = case arg of S s -> s totalBill = everything (+) queryS totalBill = everything (+) queryS transM _ = return transM _ = return advice around {transM} (arg::Employee) = case arg of E p@(P n _) _ -> do s do s <- dbLookup n; return $ E p s dbSalaries = everywhereM transM dbSalaries = everywhereM transM

19 Boilerplate 2 Reflection: Already in GHC 6.4 library Reflection: Already in GHC 6.4 library Generic map, zip Generic map, zip extQ, extT, extM extQ, extT, extM Extend a generic query/transformation/ monadic transformation by a type- specific caseExtend a generic query/transformation/ monadic transformation by a type- specific case GHC 6.4, Data.Generics.AliasGHC 6.4, Data.Generics.Alias

20 Boilerplate 3 Generalizing queries on Data (Term) Generalizing queries on Data (Term) gsize :: Data a => a -> Intgsize :: Data a => a -> Int gsize t = gsize_def `extQ` name_size `extQ` phone_sizegsize t = gsize_def `extQ` name_size `extQ` phone_size class Size a where gsize :: a -> Intclass Size a where gsize :: a -> Int instance Data t => Size t where gsize t = 1 + sum (gmapQ gsize t) instance Data t => Size t where gsize t = 1 + sum (gmapQ gsize t) class Size a => Data a where … class Size a => Data a where … This belongs to the SYB “ library ” Needed for “ every ” query

21 Boilerplate 3 (cont.) Need “ type variable over classes ” Need “ type variable over classes ” Can be encoded straightforwardly in standard HaskellCan be encoded straightforwardly in standard Haskell API of Data changed API of Data changed AOP solution cleaner AOP solution cleaner gsize t = 1 + sum (gmapQ gsize t)gsize t = 1 + sum (gmapQ gsize t) advice around {gsize} (arg::Name) = case arg of (N _) -> 1advice around {gsize} (arg::Name) = case arg of (N _) -> 1 advice around {gsize} (arg::PhoneNumber) = length arg -- another special caseadvice around {gsize} (arg::PhoneNumber) = length arg -- another special case


Download ppt "Scrap Your Boilerplate /~simonpj/papers/hmap/"

Similar presentations


Ads by Google