This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

mlang / Mlang / Interpreter.lean
7.8 kB 263 lines
1namespace Mlang 2 3abbrev Name := String 4 5inductive Effect where 6 | error : Effect 7 deriving Repr, Inhabited, BEq 8 9abbrev Effects := List Effect 10 11def Effects.contains (effects : Effects) (effect : Effect) : Bool := 12 effects.any (· == effect) 13 14def Effects.insert (effects : Effects) (effect : Effect) : Effects := 15 if effects.contains effect then effects else effect :: effects 16 17def Effects.union (lhs rhs : Effects) : Effects := 18 rhs.foldl Effects.insert lhs 19 20def Effects.erase (effects : Effects) (target : Effect) : Effects := 21 effects.filter (· != target) 22 23def Effects.render : Effects String 24 | [] => "{}" 25 | effects => 26 let names := effects.reverse.map (fun 27 | .error => "Error") 28 "{" ++ String.intercalate ", " names ++ "}" 29 30inductive Ty where 31 | int : Ty 32 | bool : Ty 33 | funTy : Ty Effects Ty Ty 34 deriving Repr, Inhabited, BEq 35 36inductive Expr where 37 | int : Int Expr 38 | bool : Bool Expr 39 | var : Name Expr 40 | add : Expr Expr Expr 41 | sub : Expr Expr Expr 42 | mul : Expr Expr Expr 43 | div : Expr Expr Expr 44 | eq : Expr Expr Expr 45 | letE : Name Expr Expr Expr 46 | ifE : Expr Expr Expr Expr 47 | tryE : Expr Expr Expr 48 | lam : Name Ty Expr Expr 49 | app : Expr Expr Expr 50 deriving Repr, Inhabited 51 52inductive Value where 53 | int : Int Value 54 | bool : Bool Value 55 | closure : Name Expr List (Name × Value) Value 56 deriving Repr, Inhabited 57 58abbrev Env := List (Name × Value) 59 60inductive RuntimeError where 61 | unboundVariable : Name RuntimeError 62 | typeError : String RuntimeError 63 | divisionByZero : RuntimeError 64 deriving Repr, Inhabited 65 66abbrev EvalM := Except RuntimeError 67 68def Env.lookup (env : Env) (name : Name) : Option Value := 69 match env with 70 | [] => none 71 | (n, v) :: rest => if n = name then some v else rest.lookup name 72 73def expectInt : Value EvalM Int 74 | .int n => .ok n 75 | _ => .error (.typeError "expected an integer") 76 77def expectBool : Value EvalM Bool 78 | .bool b => .ok b 79 | _ => .error (.typeError "expected a boolean") 80 81partial def eval (env : Env) : Expr EvalM Value 82 | .int n => .ok (.int n) 83 | .bool b => .ok (.bool b) 84 | .var name => 85 match env.lookup name with 86 | some v => .ok v 87 | none => .error (.unboundVariable name) 88 | .add lhs rhs => do 89 let l expectInt ( eval env lhs) 90 let r expectInt ( eval env rhs) 91 pure (.int (l + r)) 92 | .sub lhs rhs => do 93 let l expectInt ( eval env lhs) 94 let r expectInt ( eval env rhs) 95 pure (.int (l - r)) 96 | .mul lhs rhs => do 97 let l expectInt ( eval env lhs) 98 let r expectInt ( eval env rhs) 99 pure (.int (l * r)) 100 | .div lhs rhs => do 101 let l expectInt ( eval env lhs) 102 let r expectInt ( eval env rhs) 103 if r = 0 then 104 .error .divisionByZero 105 else 106 pure (.int (l / r)) 107 | .eq lhs rhs => do 108 let l expectInt ( eval env lhs) 109 let r expectInt ( eval env rhs) 110 pure (.bool (l = r)) 111 | .letE name value body => do 112 let value' eval env value 113 eval ((name, value') :: env) body 114 | .ifE cond thenBranch elseBranch => do 115 let c expectBool ( eval env cond) 116 if c then 117 eval env thenBranch 118 else 119 eval env elseBranch 120 | .tryE body handler => 121 match eval env body with 122 | .ok value => .ok value 123 | .error _ => eval env handler 124 | .lam param _ body => 125 pure (.closure param body env) 126 | .app fn arg => do 127 let fnVal eval env fn 128 let argVal eval env arg 129 match fnVal with 130 | .closure param body closureEnv => 131 eval ((param, argVal) :: closureEnv) body 132 | _ => 133 .error (.typeError "expected a function") 134 135def renderValue : Value String 136 | .int n => toString n 137 | .bool b => toString b 138 | .closure _ _ _ => "<closure>" 139 140abbrev TyEnv := List (Name × Ty) 141 142structure Judgment where 143 ty : Ty 144 effects : Effects 145 deriving Repr, Inhabited 146 147inductive TypeError where 148 | unboundVariable : Name TypeError 149 | mismatch : Ty Ty TypeError 150 | expectedFunction : Ty TypeError 151 deriving Repr, Inhabited 152 153abbrev CheckM := Except TypeError 154 155def TyEnv.lookup (env : TyEnv) (name : Name) : Option Ty := 156 match env with 157 | [] => none 158 | (n, ty) :: rest => if n = name then some ty else rest.lookup name 159 160def ensureType (expected actual : Ty) : CheckM Unit := 161 if expected == actual then 162 pure () 163 else 164 throw (.mismatch expected actual) 165 166def pureJudgment (ty : Ty) : Judgment := 167 { ty := ty, effects := [] } 168 169partial def inferType (env : TyEnv) : Expr CheckM Judgment 170 | .int _ => pure (pureJudgment .int) 171 | .bool _ => pure (pureJudgment .bool) 172 | .var name => 173 match env.lookup name with 174 | some ty => pure (pureJudgment ty) 175 | none => throw (.unboundVariable name) 176 | .add lhs rhs 177 | .sub lhs rhs 178 | .mul lhs rhs => do 179 let lhsJ inferType env lhs 180 let rhsJ inferType env rhs 181 ensureType .int lhsJ.ty 182 ensureType .int rhsJ.ty 183 pure { ty := .int, effects := lhsJ.effects.union rhsJ.effects } 184 | .div lhs rhs => do 185 let lhsJ inferType env lhs 186 let rhsJ inferType env rhs 187 ensureType .int lhsJ.ty 188 ensureType .int rhsJ.ty 189 pure { 190 ty := .int 191 effects := (lhsJ.effects.union rhsJ.effects).insert .error 192 } 193 | .eq lhs rhs => do 194 let lhsJ inferType env lhs 195 let rhsJ inferType env rhs 196 ensureType .int lhsJ.ty 197 ensureType .int rhsJ.ty 198 pure { ty := .bool, effects := lhsJ.effects.union rhsJ.effects } 199 | .letE name value body => do 200 let valueJ inferType env value 201 let bodyJ inferType ((name, valueJ.ty) :: env) body 202 pure { 203 ty := bodyJ.ty 204 effects := valueJ.effects.union bodyJ.effects 205 } 206 | .ifE cond thenBranch elseBranch => do 207 let condJ inferType env cond 208 ensureType .bool condJ.ty 209 let thenJ inferType env thenBranch 210 let elseJ inferType env elseBranch 211 ensureType thenJ.ty elseJ.ty 212 pure { 213 ty := thenJ.ty 214 effects := condJ.effects.union (thenJ.effects.union elseJ.effects) 215 } 216 | .tryE body handler => do 217 let bodyJ inferType env body 218 let handlerJ inferType env handler 219 ensureType bodyJ.ty handlerJ.ty 220 pure { 221 ty := bodyJ.ty 222 effects := (bodyJ.effects.erase .error).union handlerJ.effects 223 } 224 | .lam param paramTy body => do 225 let bodyJ inferType ((param, paramTy) :: env) body 226 pure (pureJudgment (.funTy paramTy bodyJ.effects bodyJ.ty)) 227 | .app fn arg => do 228 let fnJ inferType env fn 229 let argJ inferType env arg 230 match fnJ.ty with 231 | .funTy paramTy latentEffects resultTy => 232 ensureType paramTy argJ.ty 233 pure { 234 ty := resultTy 235 effects := fnJ.effects.union (argJ.effects.union latentEffects) 236 } 237 | _ => 238 throw (.expectedFunction fnJ.ty) 239 240def renderType : Ty String 241 | .int => "Int" 242 | .bool => "Bool" 243 | .funTy lhs effects rhs => s!"({renderType lhs} -> {renderType rhs} ! {effects.render})" 244 245def renderJudgment (judgment : Judgment) : String := 246 s!"{renderType judgment.ty} ! {judgment.effects.render}" 247 248def sampleProgram : Expr := 249 .letE "inc" (.lam "x" .int (.add (.var "x") (.int 1))) 250 (.app (.var "inc") (.int 41)) 251 252def lexicalScopeProgram : Expr := 253 .letE "x" (.int 10) 254 (.letE "f" (.lam "y" .int (.add (.var "x") (.var "y"))) 255 (.letE "x" (.int 100) 256 (.app (.var "f") (.int 5)))) 257 258def conditionalProgram : Expr := 259 .ifE (.eq (.mul (.int 6) (.int 7)) (.int 42)) 260 (.int 1) 261 (.int 0) 262 263end Mlang