Lift.hs (4878B)
1 module Lift where 2 3 import Data.Functor.Foldable 4 import Data.List 5 import Types 6 7 converge f a = let a' = f a in if a' == a then a else converge f a' 8 9 factorial :: AExp 10 factorial = 11 ( Lam 12 ["n"] 13 ( Let 14 "m" 15 (Call "factorial" [(ASub (Ident "n") (Number 1))]) 16 ( If 17 (ALt (Ident "n") (Number 2)) 18 (FC (Atom (Number 1))) 19 (FC (Atom (AMul (Ident "m") (Ident "n")))) 20 ) 21 ) 22 ) 23 24 three :: CExp 25 three = 26 ( Let 27 "n" 28 (Atom (Number 1)) 29 ( Let 30 "n" 31 (Atom (AAdd (Ident "n") (Number 1))) 32 ( Let 33 "n" 34 (Atom (AAdd (Ident "n") (Number 1))) 35 (FC (Atom (Ident "n"))) 36 ) 37 ) 38 ) 39 40 liftArgs :: AExp -> AExp 41 liftArgs lam@(Lam args body) = Lam (args ++ cata findVarsAExp lam) body 42 liftArgs rest = rest 43 44 -- | F-Algebras to find free variables 45 findVars :: CExpF [String] -> [String] 46 findVars (LetF ident fc rest) = converge (\\ [ident]) $ rest ++ (findVarsFC fc) 47 findVars (IfF cond t e) = t ++ e ++ (cata findVarsAExp cond) 48 findVars (FCF fc) = findVarsFC fc 49 50 findVarsFC :: Funcall -> [String] 51 findVarsFC (Atom aexp) = cata findVarsAExp aexp 52 findVarsFC (Call id args) = id : (args >>= cata findVarsAExp) 53 54 findVarsAExp :: AExpF [String] -> [String] 55 findVarsAExp (IdentF ns) = [ns] 56 findVarsAExp (LamF args cexp) = converge (\\ args) (fold findVars cexp) 57 findVarsAExp def = foldMap id def 58 59 -- replacing free variables with a new one if it matches the argument 60 61 compareNames n m = if n == m then n ++ "_" else n 62 63 -- | replace bound variables in AExps 64 65 -- >>> hoist (replaceVarsAExp "n") factorial 66 replaceVarsAExp :: String -> AExpF a -> AExpF a 67 replaceVarsAExp n (IdentF m) = IdentF $ compareNames m n 68 replaceVarsAExp n (LamF args body) = 69 LamF 70 (fmap (\x -> if x == n then x ++ "_" else x) args) 71 (cata replaceVarsCExp body n) 72 replaceVarsAExp _ rest = rest 73 74 -- | replace bound variables in CExps 75 replaceVarsCExp :: CExpF (String -> CExp) -> String -> CExp 76 replaceVarsCExp (LetF name fc restf) = do 77 env <- id 78 rest <- restf 79 let newName = compareNames name env 80 return $ Let newName (replaceVarsFC env fc) rest 81 replaceVarsCExp (IfF cond thenF elseF) = do 82 thenPart <- thenF 83 elsePart <- elseF 84 env <- id 85 return $ If (hoist (replaceVarsAExp env) cond) thenPart elsePart 86 replaceVarsCExp (FCF fc) = do 87 env <- id 88 return $ FC (replaceVarsFC env fc) 89 90 -- | replace bound variables in Function calls 91 replaceVarsFC :: String -> Funcall -> Funcall 92 replaceVarsFC n (Atom aexp) = Atom $ hoist (replaceVarsAExp n) aexp 93 replaceVarsFC n (Call name args) = 94 Call 95 (compareNames name n) 96 $ fmap (hoist (replaceVarsAExp n)) args 97 98 subVarsAExp :: ([String], AExpF a) -> AExpF ([String], a) 99 subVarsAExp (env, LamF args body) = 100 let 101 toReplace = intersect env args 102 newArgs = fmap (\x -> if x `elem` toReplace then x ++ "_" else x) args 103 newBody = foldl (cata replaceVarsCExp) body toReplace 104 in 105 LamF newArgs (cotransverse subVarsCExp (newArgs ++ env, [], newBody)) 106 subVarsAExp (env, rest) = fmap (env,) rest 107 108 {- | cotransverse of a complex expression. The first string list represents 109 | bound variables, the second one a queue of variables to be replaced 110 -} 111 subVarsCExp :: ([String], [String], CExpF a) -> CExpF ([String], [String], a) 112 subVarsCExp (env, queue, LetF name fc rest) = 113 let 114 (newName, oldNames) = 115 foldr 116 (\m (n, ns) -> if n == m then (n ++ "_", n : ns) else (n, ns)) -- repeatedly replace variables in the function call 117 (name, []) 118 queue -- make sure to do oldest first! 119 newFC = foldr replaceVarsFC fc $ oldNames \\ [newName] 120 in 121 LetF newName newFC (if name `elem` env then (env, newName : queue, rest) else (name : env, name : queue, rest)) 122 subVarsCExp (env, queue, IfF cond thenPart elsePart) = 123 IfF 124 (foldr (\x c -> hoist (replaceVarsAExp x) c) cond queue) 125 (env, queue, thenPart) 126 (env, queue, elsePart) 127 subVarsCExp (env, queue, FCF fc) = FCF $ foldr replaceVarsFC fc queue 128 129 unsafeCotransverse :: 130 (Corecursive t, Recursive a, Functor f) => 131 (f (Base a a) -> Base t (f a)) -> 132 f a -> 133 t 134 unsafeCotransverse n = ana (n . fmap project) 135 136 subVarsCExp' :: ([String], CExpF CExp) -> CExpF ([String], CExp) 137 subVarsCExp' (env, LetF name fc body) 138 | name `elem` env = 139 let 140 newName = name ++ "_" 141 newFC = replaceVarsFC newName fc 142 newBody = cata replaceVarsCExp body name 143 in 144 LetF newName newFC (newName : env, newBody) 145 | otherwise = LetF name fc (name : env, body) 146 subVarsCExp' (env, rest) = fmap (env,) rest 147 148 substitute :: CExp -> CExp 149 substitute = unsafeCotransverse subVarsCExp' . ([],)