Created
August 9, 2023 14:40
-
-
Save holoed/045603448045d3e8ab6236141fadfc19 to your computer and use it in GitHub Desktop.
Python Interpreter
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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