Last active
December 18, 2022 10:11
-
-
Save conf8o/4004c9ed7c78be397169d1c3a293439e to your computer and use it in GitHub Desktop.
lisp by python
This file contains 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
import operator as op | |
from itertools import chain | |
def car(l): | |
l = iter(l) | |
try: | |
return next(l) | |
except StopIteration: | |
return None | |
def cdr(l): | |
l = iter(l) | |
try: | |
next(l) | |
return l | |
except StopIteration: | |
return None | |
class Special: | |
def __init__(self, env): | |
self.env = env | |
def __call__(self, *args): | |
pass | |
def special(obj): | |
return issubclass(type(obj), Special) | |
class EvaluateError(Exception): | |
pass | |
class S: | |
def __init__(self, *s): | |
self.car = car(s) | |
self.cdr = cdr(s) | |
def eval(self, env): | |
f = evaluate(self.car, env) | |
if special(f): | |
return f(*self.cdr) | |
elif callable(f): | |
return f(*evaluate_list(self.cdr, env)) | |
else: | |
raise EvaluateError() | |
class SymbolError(Exception): | |
pass | |
def evaluate(obj, env): | |
if type(obj) is type and issubclass(obj, Special): | |
return obj(env) | |
elif type(obj) is S: | |
return obj.eval(env) | |
elif type(obj) is str and obj[0] == "'": | |
for e in reversed(env): | |
x = e.get(obj) | |
if x is not None: | |
return x | |
raise SymbolError(obj) | |
else: | |
return obj | |
def evaluate_list(l, env): | |
for x in l: | |
yield evaluate(x, env) | |
class Define(Special): | |
def __call__(self, label, value): | |
self.env[-1][label] = evaluate(value, self.env) | |
class LetBindingError(Exception): | |
pass | |
class Let(Special): | |
def __call__(self, bindings, expr): | |
self.env.append({}) | |
try: | |
bindings = iter(bindings) | |
for label in bindings: | |
value_s = next(bindings) | |
value = evaluate(value_s, self.env) | |
self.env[-1][label] = value | |
ret = evaluate(expr, self.env) | |
self.env.pop() | |
return ret | |
except StopIteration: | |
raise LetBindingError() | |
class Fn(Special): | |
def __call__(self, _args, exp): | |
def fn(*args): | |
bindings = chain.from_iterable(zip(_args, args)) | |
return evaluate(S(Let, bindings, exp), self.env) | |
return fn | |
environment = [{ | |
"'+": op.add, | |
"'-": op.sub, | |
"'*": op.mul, | |
"'/": op.truediv, | |
"'>": op.gt, | |
"'<": op.lt, | |
"'=": op.eq | |
}] | |
ss = [ | |
S(Define, "'x", S("'*", 120, 50)), | |
S(Let, ["'a", 80, | |
"'b", S("'*", 2, 10), | |
"'square", S(Fn, ["'x"], | |
S("'*", "'x", "'x"))], | |
S("'/", "'x", S("'square", S("'+", "'a", "'b")))) | |
] | |
for s in ss: | |
res = evaluate(s, environment) | |
print(res) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment