DrIFT-cabalized-2.2.3.2: src/Rules/FunctorM.hs
-- stub module to add your own rules.
module Rules.FunctorM (rules) where
import Data.List
import RuleUtils
rules = [
("FunctorM", userRuleFunctorM, "Generics", "derive reasonable fmapM implementation", Nothing),
("Functor", userRuleFunctor, "Generics", "derive reasonable Functor instance", Nothing),
("Foldable", userRuleFoldable, "Generics", "derive instance for Data.Foldable", Nothing),
("Traversable", userRuleTraversable, "Generics", "derive instance for Data.Traversable", Nothing),
("RMapM", userRuleRMapM, "Generics", "derive reasonable rmapM implementation", Nothing)
]
hasVar tt t = hasType (Var tt) t
hasType tt t = has t where
has t | t == tt = True
has (List t) = has t
has (Arrow a b) = has a || has b
has (LApply t ts) = any has (t:ts)
has (Tuple ts) = any has (ts)
has _ = False
userRuleFoldable D{name = name, vars = [] } = text "--" <+> text name <> text ": Cannot derive Foldable without type variables"
userRuleFoldable D{name = name, vars = vars, body=body } = ins where
(tt:rt') = reverse vars
rt = reverse rt'
fn = if null rt then text name else parens (text name <+> hsep (map text rt))
ins = text "instance" <+> text "Foldable" <+> fn <+> text "where" $$ block fs
fs = map f' $ body
combine xs = if null xs then text "Data.Monoid.mempty" else hsep (intersperse (text "`Data.Monoid.mappend`") xs)
f' Body{constructor=constructor, types=types} = text "foldMap" <+> f <+> pattern constructor types <+> equals <+> combine (concatMap g (zip types vnt)) where
vnt = varNames types
g (t,n) | not (hasVar tt t) = []
g (Var t,n) | t == tt = [parens $ f <+> n]
g (List (Var t),n) | t == tt = [parens $ text "Data.Monoid.mconcat $ Prelude.map" <+> f <+> n]
g (List t,n) = [parens $ text "Data.Monoid.mconcat $ Prelude.map" <+> lf t <+> n] where
lf t = parens $ text "\\x ->" <+> combine (g (t,x))
g (LApply t [],n) = g (t,n)
g (LApply t ts,n) = [parens $ text "Data.Foldable.foldMap" <+> f <+> n]
g (Tuple ts,n) = [parens $ text "case" <+> n <+> text "of" <+> tuple (varNames ts) <+> rArrow <+> combine (concatMap g (zip ts (varNames ts)))]
g _ = []
userRuleFunctor D{name = name, vars = [] } = text "--" <+> text name <> text ": Cannot derive Functor without type variables"
userRuleFunctor D{name = name, vars = vars, body=body } = ins where
(tt:rt') = reverse vars
rt = reverse rt'
fn = if null rt then text name else parens (text name <+> hsep (map text rt))
ins = text "instance" <+> text "Functor" <+> fn <+> text "where" $$ block fs
fs = map f' $ body
f' Body{constructor=constructor, types=types} = text "fmap" <+> text "f" <+> pattern constructor types <+> equals <+> text constructor <+> hsep (map g (zip types vnt)) where
vnt = varNames types
g (t,n) | not (hasVar tt t) = n
g (Var t,n) | t == tt = parens $ f <+> n
g (List (Var t),n) | t == tt = parens $ text "Prelude.map" <+> f <+> n
g (List t,n) = parens $ text "Prelude.map" <+> lf t <+> n where
lf t = parens $ text "\\x ->" <+> g (t,x)
g (LApply t [],n) = g (t,n)
g (LApply t ts,n) | last ts == Var tt = parens $ text "fmap" <+> f <+> n
g (Tuple ts,n) = parens $ text "case" <+> n <+> text "of" <+> tuple (varNames ts) <+> rArrow <+> tuple (map g (zip ts (varNames ts)))
g _ = empty
userRuleFunctorM D{name = name, vars = [] } = text "--" <+> text name <> text ": Cannot derive FunctorM without type variables"
userRuleFunctorM D{name = name, vars = vars, body=body } = ins where
(tt:rt') = reverse vars
rt = reverse rt'
fn = if null rt then text name else parens (text name <+> hsep (map text rt))
ins = text "instance" <+> text "FunctorM" <+> fn <+> text "where" $$ block fs
fs = map f' $ body
f' Body{constructor=constructor, types=types} = text "fmapM" <+> text "f" <+> pattern constructor types <+> equals <+> text "do" <+> hcat (map g (zip types vnt)) <+> text "return $" <+> text constructor <+> hsep vnt where
vnt = varNames types
g (t,n) | not (hasVar tt t) = empty
g (Var t,n) | t == tt = n <+> lArrow <+> text "f" <+> n <> semicolon
g (List (Var t),n) | t == tt = n <+> lArrow <+> text "mapM" <+> f <+> n <> semicolon
g (List t,n) = n <+> lArrow <+> text "mapM" <+> lf t <+> n <> semicolon where
lf t = parens $ text "\\x ->" <+> text "do" <+> g (t,x) <+> text "return" <+> x
g (LApply t [],n) = g (t,n)
g (LApply t ts,n) | last ts == Var tt = n <+> lArrow <+> text "fmapM" <+> f <+> n <> semicolon
g (Tuple ts,n) = n <+> lArrow <+> (parens $ text "do" <+> tuple (varNames ts) <+> lArrow <+> text "return" <+> n <> semicolon <+> hcat (map g (zip ts (varNames ts))) <> text "return" <+> tuple (varNames ts)) <> semicolon
g _ = empty
userRuleRMapM D{name = name, vars = vars, body=body } = ins where
--(tt:rt') = reverse vars
tt = if null vars then Con name else LApply (Con name) (map Var vars)
rt = vars
fn = if null rt then text name else parens (text name <+> hsep (map text rt))
ins = text "instance" <+> text "RMapM" <+> fn <+> text "where" $$ block fs
fs = map f' $ body
f' Body{constructor=constructor, types=types} = text "rmapM" <+> text "f" <+> pattern constructor types <+> equals <+> text "do" <+> hcat (map g (zip types vnt)) <+> text "return $" <+> text constructor <+> hsep vnt where
vnt = varNames types
g (t,n) | not (hasType tt t) = empty
g ( t,n) | t == tt = n <+> lArrow <+> text "f" <+> n <> semicolon
g (List (t),n) | t == tt = n <+> lArrow <+> text "mapM" <+> f <+> n <> semicolon
g (List t,n) = n <+> lArrow <+> text "mapM" <+> lf t <+> n <> semicolon where
lf t = parens $ text "\\x ->" <+> text "do" <+> g (t,x) <+> text "return" <+> x
g (LApply t [],n) = g (t,n)
g (LApply t ts,n) | last ts == tt = n <+> lArrow <+> text "fmapM" <+> f <+> n <> semicolon
g (Tuple ts,n) = n <+> lArrow <+> (parens $ text "do" <+> tuple (varNames ts) <+> lArrow <+> text "return" <+> n <> semicolon <+> hcat (map g (zip ts (varNames ts))) <> text "return" <+> tuple (varNames ts)) <> semicolon
g _ = empty
userRuleTraversable D{name = name, vars = [] } = text "--" <+> text name <> text ": Cannot derive Traversable without type variables"
userRuleTraversable D{name = name, vars = vars, body=body } = ins where
(tt:rt') = reverse vars
rt = reverse rt'
fn = if null rt then text name else parens (text name <+> hsep (map text rt))
ins = text "instance" <+> text "Data.Traversable.Traversable" <+> fn <+> text "where" $$ block fs
fs = map f' $ body
combine xs = if null xs then empty else text "<$>" <+> hsep (intersperse (text "<*>") xs)
f' Body{constructor=constructor, types=types} = text "traverse" <+> f <+> pattern constructor types <+> equals <+> text constructor <+> combine (map g (zip types vnt)) where
vnt = varNames types
g (t,n) | not (hasVar tt t) = text "Control.Applicative.pure" <+> n
g (Var t,n) | t == tt = f <+> n
g (List (Var t),n) | t == tt = text "traverse" <+> f <+> n
g (List t,n) = text "traverse" <+> lf t <+> n where
lf t = parens $ text "\\x ->" <+> g (t,x)
g (LApply t [],n) = g (t,n)
g (LApply t ts,n) | last ts == Var tt = text "traverse" <+> f <+> n
-- g (Tuple ts,n) = (parens $ tuple (varNames ts) <+> lArrow <+> text "return" <+> n <> semicolon <+> hcat (map g (zip ts (varNames ts))) <> text "return" <+> tuple (varNames ts)) <> semicolon
g (Tuple ts,n) = parens $ text "case" <+> n <+> text "of" <+> tuple (varNames ts) <+> rArrow <+> text ("(" ++ replicate (length ts - 1) ',' ++ ")") <+> combine (map g (zip ts (varNames ts)))
g _ = empty