Skip to content

Instantly share code, notes, and snippets.

@amitdev
Last active August 29, 2015 14:04
Show Gist options
  • Save amitdev/200bd0bc38a503ed5d73 to your computer and use it in GitHub Desktop.
Save amitdev/200bd0bc38a503ed5d73 to your computer and use it in GitHub Desktop.
from numbers import Number
class M(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return "%s(%r)" % (self.__class__.__name__, self.val)
def __eq__(self, other):
return self.val == other.val
class Error(M):
def __call__(self, _):
return self
class State(M):
def __init__(self, val, count=0, old=None, f=None):
super(State, self).__init__(val)
self.count = count
self.old = old
self.f = f
def __call__(self, count):
if not self.old:
return State(self.val, count)
else:
new_state = self.old(count)
return self.f(new_state.val)(new_state.count)
def __eq__(self, other):
return self.val == other.val and self.count == other.count
class Counter(State):
def __call__(self, count):
return State(self.val, count+1)
def unit(v):
return State(v)
def bind(m, f):
if isinstance(m, Error):
return m
return State(m.val, old=m, f=f)
class Num(object):
def __init__(self, val):
self.val = val
def evaluate(self, env):
if isinstance(self.val, Number):
return unit(self.val)
else:
return Error("%s is not a number" % self.val)
class Var(object):
def __init__(self, name):
self.name = name
def evaluate(self, env):
try:
return unit(env[self.name])
except KeyError:
return Error("Variable %r not defined" % self.name)
class Add(object):
def __init__(self, left, right):
self.left = left
self.right = right
def evaluate(self, env):
return bind(self.left.evaluate(env), lambda x: bind(self.right.evaluate(env), lambda y: bind(Counter(None), lambda t: unit(x+y))))
assert (Num(1).evaluate({}))(0) == State(1,0)
assert (Var("foo").evaluate({"foo":3}))(0) == State(3,0)
assert (Add(Num(1), Num(2)).evaluate({"foo":3}))(0) == State(3, 1)
assert (Add(Num(1), Add(Var("foo"), Num(2))).evaluate({"foo":3}))(0) == State(6, 2)
assert (Add(Num(1), Add(Var("foo"), Add(Var("foo"), Num(13)))).evaluate({"foo":3}))(0) == State(20, 3)
#Errors
assert (Add(Num(1), Num("2")).evaluate({"foo":3}))(0) == Error("2 is not a number")
assert (Add(Num(1), Var("fo")).evaluate({"foo":3}))(0) == Error("Variable 'fo' not defined")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment