|
| 1 | +module CCC.CompilerElliott |
| 2 | + ( Cat (..) |
| 3 | + , compile |
| 4 | + , absCCC |
| 5 | + , eval |
| 6 | + , evalTop |
| 7 | + , Value (..) |
| 8 | + ) where |
| 9 | + |
| 10 | +import Parser (Environment, Expr (..)) |
| 11 | + |
| 12 | +-- Untyped CCC terms ----------------------------------------------------------- |
| 13 | + |
| 14 | +data Cat |
| 15 | + = CVar String -- free variable (eliminated by absCCC) |
| 16 | + | CId -- id |
| 17 | + | CComp Cat Cat -- f . g |
| 18 | + | CFst | CSnd -- projections |
| 19 | + | CFan Cat Cat -- ⟨f, g⟩ (△) |
| 20 | + | CApply -- apply (eval morphism) |
| 21 | + | CCurry Cat -- curry f |
| 22 | + | CConst Integer -- constant integer |
| 23 | + | CAdd | CSub | CMul |
| 24 | + | CEql | CLeq | CGeq |
| 25 | + | CFix Cat -- fix (step) |
| 26 | + deriving (Show, Eq) |
| 27 | + |
| 28 | +-- Compilation: Expr → Cat ----------------------------------------------------- |
| 29 | + |
| 30 | +compile :: Environment -> Expr -> Cat |
| 31 | +compile _ (Int i) = CConst i |
| 32 | +compile env (Var x) = resolveVar env x |
| 33 | +compile env (App f a) |
| 34 | + | isFixOp env f = compileFix env a |
| 35 | +compile env (App f a) = CComp CApply (CFan (compile env f) (compile env a)) |
| 36 | +compile env (Lam x body) = CCurry (absCCC x (compile env body)) |
| 37 | + |
| 38 | +resolveVar :: Environment -> String -> Cat |
| 39 | +resolveVar env x = case lookup x env of |
| 40 | + Just e -> compile env e |
| 41 | + Nothing -> resolvePrim x |
| 42 | + |
| 43 | +resolvePrim :: String -> Cat |
| 44 | +resolvePrim "+" = CCurry CAdd |
| 45 | +resolvePrim "-" = CCurry CSub |
| 46 | +resolvePrim "*" = CCurry CMul |
| 47 | +resolvePrim "sub" = CCurry CSub |
| 48 | +resolvePrim "sub1" = CCurry (CComp CSub (CFan CSnd (CConst 1))) |
| 49 | +resolvePrim "is0" = CCurry (CComp CEql (CFan CSnd (CConst 0))) |
| 50 | +resolvePrim "eql" = CCurry CEql |
| 51 | +resolvePrim "leq" = CCurry CLeq |
| 52 | +resolvePrim "geq" = CCurry CGeq |
| 53 | +resolvePrim "true" = CSnd -- Scott TRUE = snd |
| 54 | +resolvePrim "false" = CFst -- Scott FALSE = fst |
| 55 | +resolvePrim "if" = CCurry (CCurry (CCurry ifBody)) |
| 56 | + where |
| 57 | + -- context: (((env, sel), t), e) |
| 58 | + sel = CComp CSnd (CComp CFst CFst) -- selector |
| 59 | + t = CComp CSnd CFst -- then branch |
| 60 | + e = CSnd -- else branch |
| 61 | + ifBody = CComp CApply (CFan sel (CFan e t)) |
| 62 | +resolvePrim name = CVar name |
| 63 | + |
| 64 | +-- Fixpoint detection ---------------------------------------------------------- |
| 65 | + |
| 66 | +isFixOp :: Environment -> Expr -> Bool |
| 67 | +isFixOp env = go [] |
| 68 | + where |
| 69 | + go _ (Int _) = False |
| 70 | + go _ (Lam _ _) = False |
| 71 | + go _ (App _ _) = False |
| 72 | + go seen (Var name) |
| 73 | + | name == "y" || name == "fix" = True |
| 74 | + | name `elem` seen = False |
| 75 | + | otherwise = maybe False (go (name : seen)) (lookup name env) |
| 76 | + |
| 77 | +compileFix :: Environment -> Expr -> Cat |
| 78 | +compileFix env (Lam self body) = |
| 79 | + CFix (CCurry (absCCC self (compile env body))) |
| 80 | +compileFix _ _ = error "fix expects a lambda step function" |
| 81 | + |
| 82 | +-- Elliott's bracket abstraction ----------------------------------------------- |
| 83 | +-- |
| 84 | +-- The three core rules mirror SKI bracket abstraction: |
| 85 | +-- [x] x = snd (cf. I) |
| 86 | +-- [x] e = e . fst (x not in e) (cf. K) |
| 87 | +-- [x] (f @ g) = apply . ⟨[x] f, [x] g⟩ (cf. S) |
| 88 | +-- |
| 89 | +-- Plus structural rules for Cat constructors that arise from compilation. |
| 90 | + |
| 91 | +absCCC :: String -> Cat -> Cat |
| 92 | +-- Core rules: |
| 93 | +absCCC x (CVar y) | x == y = CSnd |
| 94 | +absCCC x t | not (freeIn x t) = CComp t CFst |
| 95 | +absCCC x (CComp CApply (CFan f g)) = |
| 96 | + CComp CApply (CFan (absCCC x f) (absCCC x g)) |
| 97 | +-- Structural rules: |
| 98 | +absCCC x (CFan f g) = CFan (absCCC x f) (absCCC x g) |
| 99 | +absCCC x (CComp f g) = CComp (absCCC x f) (CFan (absCCC x g) CSnd) |
| 100 | +absCCC x (CCurry f) = CCurry (CComp (absCCC x f) assocR) |
| 101 | + where |
| 102 | + -- assocR : ((ctx, x), y) → ((ctx, y), x) |
| 103 | + assocR = CFan (CFan (CComp CFst CFst) CSnd) (CComp CSnd CFst) |
| 104 | +absCCC x (CFix f) = CFix (absCCC x f) |
| 105 | +absCCC _ t = error $ "absCCC: unexpected term " ++ show t |
| 106 | + |
| 107 | +freeIn :: String -> Cat -> Bool |
| 108 | +freeIn x (CVar y) = x == y |
| 109 | +freeIn x (CComp f g) = freeIn x f || freeIn x g |
| 110 | +freeIn x (CFan f g) = freeIn x f || freeIn x g |
| 111 | +freeIn x (CCurry f) = freeIn x f |
| 112 | +freeIn x (CFix f) = freeIn x f |
| 113 | +freeIn _ _ = False |
| 114 | + |
| 115 | +-- Untyped interpreter --------------------------------------------------------- |
| 116 | + |
| 117 | +data Value |
| 118 | + = VInt Integer |
| 119 | + | VPair Value Value |
| 120 | + | VFun (Value -> Value) |
| 121 | + |
| 122 | +instance Show Value where |
| 123 | + show (VInt i) = show i |
| 124 | + show (VPair a b) = "(" ++ show a ++ ", " ++ show b ++ ")" |
| 125 | + show (VFun _) = "<fun>" |
| 126 | + |
| 127 | +vUnit :: Value |
| 128 | +vUnit = VPair (VInt 0) (VInt 0) |
| 129 | + |
| 130 | +evalTop :: Cat -> Integer |
| 131 | +evalTop cat = case eval cat vUnit of |
| 132 | + VInt i -> i |
| 133 | + v -> error $ "evalTop: expected integer, got " ++ show v |
| 134 | + |
| 135 | +eval :: Cat -> Value -> Value |
| 136 | +eval CId v = v |
| 137 | +eval (CComp f g) v = eval f (eval g v) |
| 138 | +eval CFst (VPair a _) = a |
| 139 | +eval CSnd (VPair _ b) = b |
| 140 | +eval (CFan f g) v = VPair (eval f v) (eval g v) |
| 141 | +eval CApply (VPair f x) = applyVal f x |
| 142 | +eval (CCurry f) v = VFun (\x -> eval f (VPair v x)) |
| 143 | +eval (CConst i) _ = VInt i |
| 144 | +eval CAdd (VPair (VInt a) (VInt b)) = VInt (a + b) |
| 145 | +eval CSub (VPair (VInt a) (VInt b)) = VInt (a - b) |
| 146 | +eval CMul (VPair (VInt a) (VInt b)) = VInt (a * b) |
| 147 | +eval CEql (VPair (VInt a) (VInt b)) = scottBool (a == b) |
| 148 | +eval CLeq (VPair (VInt a) (VInt b)) = scottBool (a <= b) |
| 149 | +eval CGeq (VPair (VInt a) (VInt b)) = scottBool (a >= b) |
| 150 | +eval (CFix step) v = let rec = VFun (\x -> eval (CFix step) x) |
| 151 | + in eval step (VPair rec v) |
| 152 | +eval t v = error $ "eval: stuck on " ++ show t ++ " with " ++ show v |
| 153 | + |
| 154 | +scottBool :: Bool -> Value |
| 155 | +scottBool True = VFun (\_ -> VFun id) -- TRUE = snd: λt e. e |
| 156 | +scottBool False = VFun (\x -> VFun (const x)) -- FALSE = fst: λt e. t |
| 157 | + |
| 158 | +applyVal :: Value -> Value -> Value |
| 159 | +applyVal (VFun f) x = f x |
| 160 | +applyVal v _ = error $ "applyVal: not a function: " ++ show v |
0 commit comments