Skip to content

Instantly share code, notes, and snippets.

@holoed
Created August 9, 2023 14:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save holoed/045603448045d3e8ab6236141fadfc19 to your computer and use it in GitHub Desktop.
Save holoed/045603448045d3e8ab6236141fadfc19 to your computer and use it in GitHub Desktop.
Python Interpreter
from dataclasses import dataclass
from typing import Callable, Generic, TypeVar, Dict
T = TypeVar('T')
V = TypeVar('V')
R = TypeVar('R')
class Reader(Generic[R, T]):
def __init__(self, func: Callable[[R], T]):
self.func = func
def __call__(self, ctx: R) -> T:
return self.func(ctx)
def bind(m: Reader[T, R], f: Callable[[T], Reader[T, R]]) -> Reader[T, R]:
return Reader(lambda ctx: f(m(ctx))(ctx))
def ask() -> Reader[T, R]:
return Reader(lambda ctx: ctx)
def local(f: Callable[[T], V], m: Reader[T, R]) -> Reader[V, R]:
return Reader(lambda ctx: m(f(ctx)))
def unit(x: T) -> Reader[T, R]:
return Reader(lambda ctx: x)
@dataclass
class Prim:
pass
@dataclass
class I(Prim):
value: int
@dataclass
class B(Prim):
value: bool
@dataclass
class Expr:
pass
@dataclass
class Lit(Expr):
value: Prim
@dataclass
class Var(Expr):
value: str
@dataclass
class App(Expr):
e1: Expr
e2: Expr
@dataclass
class Lam(Expr):
n: str
e: Expr
@dataclass
class Let(Expr):
n: str
e1: Expr
e2: Expr
@dataclass
class IfThenElse(Expr):
e1: Expr
e2: Expr
e3: Expr
@dataclass
class Result:
pass
@dataclass
class Value(Result):
value: Prim
@dataclass
class Function(Result):
value: Callable[[Result], Reader[Result, Dict[str, Result]]]
@dataclass
class Error(Result):
value: str
def app_helper(r: Result, e2: Expr):
match r:
case Function(f):
return bind(interp(e2), f)
def if_helper(p: Result, e1: Expr, e2: Expr):
match p:
case Value(B(b)):
if (b): return interp(e1)
else: return interp(e2)
def interp(exp: Expr) -> Reader[Result, Dict[str, Result]]:
match exp:
case Lit(value):
return unit(Value(value))
case Var(s):
return bind(ask(), lambda ctx: unit(ctx[s]))
case Lam(s, e):
return bind(ask(), lambda ctx: unit(Function(lambda r: local(lambda ctx2: {**(ctx | ctx2), s:r}, interp(e)))))
case App(e1, e2):
return bind(interp(e1), lambda r: app_helper(r, e2))
case Let(s, e1, e2):
return bind(interp(e1), lambda r: local(lambda ctx: {**ctx, s:r}, interp(e2)))
case IfThenElse(e1, e2, e3):
return bind(interp(e1), lambda p: if_helper(p, e2, e3))
def op(op: str, x: Result, y: Result):
match (x, y):
case (Value(I(v)), Value(I(w))):
match op:
case "-": return Value(I(v - w))
case "*": return Value(I(v * w))
case "==": return Value(B(v == w))
env : Dict[str, Result] = {
"-": Function(lambda x: unit(Function(lambda y: unit (op("-", x, y))))),
"*": Function(lambda x: unit(Function(lambda y: unit (op("*", x, y))))),
"==": Function(lambda x: unit(Function(lambda y: unit (op("==", x, y))))),
}
ast = Let ("fac",
Lam ("n",
IfThenElse (App (App (Var ("=="), Var ("n")), Lit (I (0))),
Lit (I (1)),
(App (App (Var ("*"), Var ("n")),
(App (Var ("fac"), App (App (Var ("-"), Var ("n")), Lit (I (1))))))))),
App (Var("fac"), Lit (I (5))))
print(interp(ast)(env))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment