-- | Translate to the core language module Transfer.SyntaxToCore where import Transfer.Syntax.Abs import Transfer.Syntax.Print import Control.Monad.State import Data.List import Data.Maybe import qualified Data.Set as Set import Data.Set (Set) import qualified Data.Map as Map import Data.Map (Map) import Data.Monoid import Debug.Trace type C a = State CState a type CState = Integer declsToCore :: [Decl] -> [Decl] declsToCore m = evalState (declsToCore_ m) newState declsToCore_ :: [Decl] -> C [Decl] declsToCore_ = deriveDecls >>> replaceCons >>> compilePattDecls >>> desugar >>> optimize optimize :: [Decl] -> C [Decl] optimize = removeUselessMatch >>> betaReduce newState :: CState newState = 0 -- -- * Pattern equations -- compilePattDecls :: [Decl] -> C [Decl] compilePattDecls [] = return [] compilePattDecls (d@(ValueDecl x _ _):ds) = do let (xs,rest) = span (isValueDecl x) ds d <- mergeDecls (d:xs) rs <- compilePattDecls rest return (d:rs) compilePattDecls (d:ds) = liftM (d:) (compilePattDecls ds) -- | Take a non-empty list of pattern equations for the same -- function, and produce a single declaration. mergeDecls :: [Decl] -> C Decl mergeDecls ds@(ValueDecl x p _:_) = do let cs = [ (ps,rhs) | ValueDecl _ ps rhs <- ds ] (pss,rhss) = unzip cs n = length p when (not (all ((== n) . length) pss)) $ fail $ "Pattern count mismatch for " ++ printTree x vs <- replicateM n freshIdent let cases = map (\ (ps,rhs) -> Case (mkPRec ps) rhs) cs c = ECase (mkERec (map EVar vs)) cases f = foldr (EAbs . VVar) c vs return $ ValueDecl x [] f where mkRec r f = r . zipWith (\i e -> f (Ident ("p"++show i)) e) [0..] mkPRec = mkRec PRec FieldPattern mkERec xs | null xs = EEmptyRec | otherwise = mkRec ERec FieldValue xs -- -- * Derived function definitions -- deriveDecls :: [Decl] -> C [Decl] deriveDecls ds = liftM concat (mapM der ds) where ts = dataTypes ds der (DeriveDecl (Ident f) t) = case lookup f derivators of Just d -> d t k cs _ -> fail $ "Don't know how to derive " ++ f where (k,cs) = getDataType ts t der d = return [d] type Derivator = Ident -> Exp -> [(Ident,Exp)] -> C [Decl] derivators :: [(String, Derivator)] derivators = [ ("composOp", deriveComposOp), ("show", deriveShow), ("eq", deriveEq), ("ord", deriveOrd) ] deriveComposOp :: Derivator deriveComposOp t k cs = do a <- freshIdent c <- freshIdent f <- freshIdent x <- freshIdent let co = Ident ("composOp_" ++ printTree t) e = EVar pv = VVar infixr 3 --> (-->) = EPiNoVar ta = EApp (e t) (e a) tc = EApp (e t) (e c) infixr 3 \-> (\->) = EAbs mkCase ci ct = do vars <- replicateM (arity ct) freshIdent -- FIXME: the type argument to f is wrong if the constructor -- has a dependent type -- FIXME: make a special case for lists? let rec v at = case at of EApp (EVar t') _ | t' == t -> apply (e f) [at, e v] _ -> e v calls = zipWith rec vars (argumentTypes ct) return $ Case (PCons ci (map PVar vars)) (apply (e ci) calls) cases <- mapM (uncurry mkCase) cs let cases' = cases ++ [Case PWild (e x)] return $ [TypeDecl co $ EPi (pv c) EType $ (EPi (pv a) EType $ ta --> ta) --> tc --> tc, ValueDecl co [] $ VWild \-> pv f \-> pv x \-> ECase (e x) cases'] deriveShow :: Derivator deriveShow t k cs = fail $ "derive show not implemented" deriveEq :: Derivator deriveEq t k cs = fail $ "derive eq not implemented" deriveOrd :: Derivator deriveOrd t k cs = fail $ "derive ord not implemented" -- -- * Constructor patterns and applications. -- type DataConsInfo = Map Ident Int consArities :: [Decl] -> DataConsInfo consArities ds = Map.fromList [ (c, arity t) | DataDecl _ _ cs <- ds, ConsDecl c t <- cs ] -- | Get the arity of a function type. arity :: Exp -> Int arity = length . argumentTypes -- | Get the argument type of a function type. Note that -- the returned types may contains free variables -- which should be bound to the values of earlier arguments. argumentTypes :: Exp -> [Exp] argumentTypes e = case e of EPi _ t e' -> t : argumentTypes e' EPiNoVar t e' -> t : argumentTypes e' _ -> [] -- | Fix up constructor patterns and applications. replaceCons :: [Decl] -> C [Decl] replaceCons ds = mapM f ds where cs = consArities ds isCons id = id `Map.member` cs f :: Tree a -> C (Tree a) f t = case t of -- get rid of the PConsTop hack PConsTop id p1 ps -> f (PCons id (p1:ps)) -- replace patterns C where C is a constructor with (C) PVar id | isCons id -> return $ PCons id [] -- eta-expand constructors. betaReduce will remove any beta -- redexes produced here. EVar id | isCons id -> do let Just n = Map.lookup id cs vs <- replicateM n freshIdent let c = apply t (map EVar vs) return $ foldr (EAbs . VVar) c vs _ -> composOpM f t -- -- * Do simple beta reductions. -- betaReduce :: [Decl] -> C [Decl] betaReduce = return . map f where f :: Tree a -> Tree a f t = case t of EApp (EAbs (VVar x) b) e | countFreeOccur x b == 1 -> f (subst x e b) _ -> composOp f t -- -- * Remove useless pattern matching. -- removeUselessMatch :: [Decl] -> C [Decl] removeUselessMatch = return . map f where f :: Tree a -> Tree a f x = case x of -- replace \x -> case x of { y -> e } with \y -> e, -- if x is not free in e -- FIXME: this checks the result of the recursive call, -- can we do something about this? EAbs (VVar x) b -> case f b of ECase (EVar x') [Case (PVar y) e] | x' == x && not (x `isFreeIn` e) -> f (EAbs (VVar y) e) e -> EAbs (VVar x) e -- for value declarations without patterns, compilePattDecls -- generates pattern matching on the empty record, remove these ECase EEmptyRec [Case (PRec []) e] -> f e -- if the pattern matching is on a single field of a record expression -- with only one field, there is no need to wrap it in a record ECase (ERec [FieldValue x e]) cs | all (isSingleFieldPattern x) [ p | Case p _ <- cs] -> f (ECase e [ Case p r | Case (PRec [FieldPattern _ p]) r <- cs ]) -- In cases: remove record field patterns which only bind unused variables Case (PRec fps) e -> Case (f (PRec (fps \\ unused))) (f e) where unused = [fp | fp@(FieldPattern l (PVar id)) <- fps, not (id `isFreeIn` e)] -- Remove wild card patterns in record patterns PRec fps -> PRec (map f (fps \\ wildcards)) where wildcards = [fp | fp@(FieldPattern _ PWild) <- fps] _ -> composOp f x isSingleFieldPattern :: Ident -> Pattern -> Bool isSingleFieldPattern x p = case p of PRec [FieldPattern y _] -> x == y _ -> False -- -- * Remove simple syntactic sugar. -- desugar :: [Decl] -> C [Decl] desugar = return . map f where f :: Tree a -> Tree a f x = case x of EIf exp0 exp1 exp2 -> ifBool <| exp0 <| exp1 <| exp2 EPiNoVar exp0 exp1 -> EPi VWild <| exp0 <| exp1 EOr exp0 exp1 -> andBool <| exp0 <| exp1 EAnd exp0 exp1 -> orBool <| exp0 <| exp1 EEq exp0 exp1 -> appIntBin "eq" <| exp0 <| exp1 ENe exp0 exp1 -> appIntBin "ne" <| exp0 <| exp1 ELt exp0 exp1 -> appIntBin "lt" <| exp0 <| exp1 ELe exp0 exp1 -> appIntBin "le" <| exp0 <| exp1 EGt exp0 exp1 -> appIntBin "gt" <| exp0 <| exp1 EGe exp0 exp1 -> appIntBin "ge" <| exp0 <| exp1 EAdd exp0 exp1 -> appIntBin "add" <| exp0 <| exp1 ESub exp0 exp1 -> appIntBin "sub" <| exp0 <| exp1 EMul exp0 exp1 -> appIntBin "mul" <| exp0 <| exp1 EDiv exp0 exp1 -> appIntBin "div" <| exp0 <| exp1 EMod exp0 exp1 -> appIntBin "mod" <| exp0 <| exp1 ENeg exp0 -> appIntUn "neg" <| exp0 _ -> composOp f x where g <| x = g (f x) -- -- * Integers -- appIntUn :: String -> Exp -> Exp appIntUn f e = EApp (var ("prim_"++f++"_Int")) e appIntBin :: String -> Exp -> Exp -> Exp appIntBin f e1 e2 = EApp (EApp (var ("prim_"++f++"_Int")) e1) e2 -- -- * Booleans -- andBool :: Exp -> Exp -> Exp andBool e1 e2 = ifBool e1 e2 (var "False") orBool :: Exp -> Exp -> Exp orBool e1 e2 = ifBool e1 (var "True") e2 ifBool :: Exp -> Exp -> Exp -> Exp ifBool c t e = ECase c [Case (PCons (Ident "True") []) t, Case (PCons (Ident "False") []) e] -- -- * Substitution -- subst :: Ident -> Exp -> Exp -> Exp subst x e = f where f :: Tree a -> Tree a f t = case t of ELet defs exp3 | x `Set.member` letDefBinds defs -> ELet [ LetDef id (f exp1) exp2 | LetDef id exp1 exp2 <- defs] exp3 Case p e | x `Set.member` binds p -> t EAbs (VVar id) _ | x == id -> t EPi (VVar id) exp1 exp2 | x == id -> EPi (VVar id) (f exp1) exp2 EVar i | i == x -> e _ -> composOp f t -- -- * Abstract syntax utilities -- var :: String -> Exp var s = EVar (Ident s) -- | Apply an expression to a list of arguments. apply :: Exp -> [Exp] -> Exp apply = foldl EApp -- | Get an identifier which cannot occur in user-written -- code, and which has not been generated before. freshIdent :: C Ident freshIdent = do i <- get put (i+1) return (Ident ("x_"++show i)) -- | Get the variables bound by a set of let definitions. letDefBinds :: [LetDef] -> Set Ident letDefBinds defs = Set.fromList [ id | LetDef id _ _ <- defs] letDefTypes :: [LetDef] -> [Exp] letDefTypes defs = [ exp1 | LetDef _ exp1 _ <- defs ] letDefRhss :: [LetDef] -> [Exp] letDefRhss defs = [ exp2 | LetDef _ _ exp2 <- defs ] -- | Get the free variables in an expression. freeVars :: Exp -> Set Ident freeVars = f where f :: Tree a -> Set Ident f t = case t of ELet defs exp3 -> Set.unions $ (Set.unions (f exp3:map f (letDefRhss defs)) Set.\\ letDefBinds defs) :map f (letDefTypes defs) ECase exp cases -> f exp `Set.union` Set.unions [ f e Set.\\ binds p | Case p e <- cases] EAbs (VVar id) exp -> Set.delete id (f exp) EPi (VVar id) exp1 exp2 -> f exp1 `Set.union` Set.delete id (f exp2) EVar i -> Set.singleton i _ -> composOpMonoid f t isFreeIn :: Ident -> Exp -> Bool isFreeIn x e = countFreeOccur x e > 0 -- | Count the number of times a variable occurs free in an expression. countFreeOccur :: Ident -> Exp -> Int countFreeOccur x = f where f :: Tree a -> Int f t = case t of ELet defs _ | x `Set.member` letDefBinds defs -> sum (map f (letDefTypes defs)) Case p e | x `Set.member` binds p -> 0 EAbs (VVar id) _ | id == x -> 0 EPi (VVar id) exp1 _ | id == x -> f exp1 EVar id | id == x -> 1 _ -> composOpFold 0 (+) f t -- | Get the variables bound by a pattern. binds :: Pattern -> Set Ident binds = f where f :: Tree a -> Set Ident f p = case p of -- replaceCons removes non-variable PVars PVar id -> Set.singleton id _ -> composOpMonoid f p -- | Checks if a declaration is a value declaration -- of the given identifier. isValueDecl :: Ident -> Decl -> Bool isValueDecl x (ValueDecl y _ _) = x == y isValueDecl _ _ = False -- -- * Data types -- type DataTypes = Map Ident (Exp,[(Ident,Exp)]) -- | Get a map of data type names to the type of the type constructor -- and all data constructors with their types. dataTypes :: [Decl] -> Map Ident (Exp,[(Ident,Exp)]) dataTypes ds = Map.fromList [ (i,(t,[(c,ct) | ConsDecl c ct <- cs])) | DataDecl i t cs <- ds] getDataType :: DataTypes -> Ident -> (Exp,[(Ident,Exp)]) getDataType ts i = fromMaybe (error $ "Data type " ++ printTree i ++ " not found") (Map.lookup i ts) -- -- * Utilities -- infixl 1 >>> (>>>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c f >>> g = (g =<<) . f