Last active
August 29, 2015 14:04
-
-
Save amitdev/200bd0bc38a503ed5d73 to your computer and use it in GitHub Desktop.
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
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