For learning purpose, I've written a simple lambda calculus interpreter (plus 'Add'). I would like it to be the cleanest and most idiomatic possible.
Can we make it as neat as the Haskell version?
# lambda interpreter example. # Values: Num, Fun & Wrong. # Terms: Cons, Var, Lam, App & Add. class Num: def __init__(self, v): self.v = v def __str__(self): return str(self.v) class Fun: def __init__(self, f): self.f = f def __call__(self, *args, **kargs): return self.f(*args, **kargs) def __str__(self): return 'function' class Wrong: def __str__(self): return 'Wrong' def add(v1, v2): return Num(v1.v + v2.v) def apply(v1, v2): return v1(v2) class Cons: def __init__(self, v): self.v = int(v) def interp(self, env): return Num(self.v) class Var: def __init__(self, x): self.x = x def interp(self, env): return env[self.x] class Lam: def __init__(self, arg, body): self.arg = arg self.body = body def interp(self, env): def f(v): env2 = env.copy() env2[self.arg] = v return self.body.interp(env2) return Fun(f) class App: def __init__(self, fun, param): self.fun = fun self.param = param def interp(self, env): return apply(self.fun.interp(env), self.param.interp(env)) class Add: def __init__(self, a, b): self.a = a self.b = b def interp(self, env): return add(self.a.interp(env), self.b.interp(env)) expr = App( Lam('x', Add(Var('x'), Var('x'))), Add(Cons(10), Cons(11)) ) print(expr.interp({}))