Skip to content

Instantly share code, notes, and snippets.

@conf8o
Last active December 18, 2022 10:11
Show Gist options
  • Save conf8o/4004c9ed7c78be397169d1c3a293439e to your computer and use it in GitHub Desktop.
Save conf8o/4004c9ed7c78be397169d1c3a293439e to your computer and use it in GitHub Desktop.
lisp by python
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