Skip to content

Instantly share code, notes, and snippets.

@debetimi
Last active August 29, 2015 14:02
Show Gist options
  • Save debetimi/96d080684c5bd7906866 to your computer and use it in GitHub Desktop.
Save debetimi/96d080684c5bd7906866 to your computer and use it in GitHub Desktop.
Reactive Programming Baby Steps
from collections import namedtuple
enum = namedtuple('Operations', ['add', 'subtract', 'multiply', 'divide'])
operations = enum(add='+', subtract="-", multiply="*", divide="/")
class Relation:
def __init__(self, a, b, op):
self.a = a
self.b = b
self.op = op
def can_calculate(self, var):
if self.has_dependency(var):
return False;
return self.a.has_value(var) and self.b.has_value(var)
def value(self):
if self.op == operations.add:
return self.a.get() + self.b.get()
elif self.op == operations.subtract:
return self.a.get() - self.b.get()
def unlock(self):
if self.a.locked:
self.a.unlock()
if self.b.locked:
self.b.unlock()
def has_dependency(self, other):
return self.a == other or self.b == other
class Var:
def __init__(self, value=None):
self.value = value
self.relationships = []
self.locked = value != None
self.is_const = value != None
def get(self, dependency=None):
if self.is_const:
return self.value
for relation in self.relationships:
if relation.has_dependency(dependency):
continue
if relation.can_calculate(self):
self.lock()
return relation.value()
return None
def add_relation(self, relation):
self.relationships.append(relation)
def set(self, value):
if self.locked:
raise Exception("Value set by dependecies, must free dependent variable")
self.value = value
self.is_const = True
def has_value(self, dependency=None):
return self.get(dependency) is not None
def lock(self):
self.locked = True
def unlock(self):
if self.locked:
self.locked = False
self.unlock_relationships()
def free(self):
if not self.is_const:
print "FREEING A NON CONSTANT IS A NO-OP"
return
self.unlock()
self.is_const = False
self.value = None
def unlock_relationships(self):
for relation in self.relationships:
relation.unlock()
def __add__(self, that):
e = Var()
if Var.is_numeric(that):
constant = Var(that)
e.add_relation(Relation(self, constant, operations.add))
self.add_relation(Relation(e, constant, operations.subtract))
elif isinstance(that, Var):
e.add_relation(Relation(self, that, operations.add))
self.add_relation(Relation(e, that, operations.subtract))
that.add_relation(Relation(e, self, operations.subtract))
return e
def __sub__(self, that):
e = Var()
e.add_relation(Relation(self, that, operations.subtract))
self.add_relation(Relation(e, that, operations.add))
that.add_relation(Relation(self, e, operations.subtract))
return e
def __str__(self):
return str(self.get())
def __repr__(self):
return self.__str__()
@staticmethod
def is_numeric(x):
return isinstance(x, int) or isinstance(x, float) or isinstance(x, long)
In [1]: from var import *
In [2]: a = Var()
In [3]: b = Var()
In [4]: c = a + b
In [5]: c
Out[5]: None
In [6]: a
Out[6]: None
In [7]: b
Out[7]: None
In [8]: a.set(1)
In [9]: c.set(1)
In [10]: b
Out[10]: 0
In [11]: a
Out[11]: 1
In [12]: c
Out[12]: 1
In [13]: b.set(3)
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
/home/tokah/Desktop/<ipython-input-13-c0c349896a0d> in <module>()
----> 1 b.set(3)
/home/tokah/Desktop/var.py in set(self, value)
54 def set(self, value):
55 if self.locked:
---> 56 raise Exception("Value set by dependecies, must free dependent variable")
57 self.value = value
58 self.is_const = True
Exception: Value set by dependecies, must free dependent variable
In [14]: a.free()
In [15]: a
Out[15]: None
In [16]: b
Out[16]: None
In [17]: c
Out[17]: 1
In [18]: b.set(3)
In [19]: a
Out[19]: -2
In [20]: b
Out[20]: 3
In [21]: c
Out[21]: 1
In [22]:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment