~nch/glue

b3563823eeda77be215f5c4c90fabca65798f60b — nc 1 year, 2 months ago 64861b6
different approach -- represent everything as tables -- so far graph construction works
2 files changed, 70 insertions(+), 70 deletions(-)

M dataflow.py
M table.py
M dataflow.py => dataflow.py +67 -70
@@ 1,74 1,71 @@
from dataclasses import dataclass
from typing import *
from table import Table

class Stream:
    def __init__(self, f):
        self.f = f
        self.i = 0
        self.vals = []
        self.nexting = False

    def __getitem__(self, i):
        if self.nexting:
            raise Exception("Already nexting!")
        if i > len(self.vals) - 1:
            self.nexting = True
            r = self.f()
            self.nexting = False
            if isinstance(r, Stream):
                r = next(r)
            self.vals.append(r)
        return self.vals[i]

    def __next__(self):
        r = self[self.i]
        self.i += 1
        return r

def fby(x, y):
    y.vals.insert(0, x)
    return y

def where(env, target, **kwargs):
    for k, v in kwargs.items():
        env[k] = v
    return Stream(lambda: env[target])

def next_(s):
    it = Stream(s)
    next(it)
    return it


s1 = Stream(lambda: 1)
assert next(s1) == 1
assert next(s1) == 1
assert next(s1) == 1

s2 = fby(1, fby(2, Stream(lambda: 3)))
assert next(s2) == 1
assert next(s2) == 2
assert next(s2) == 3
assert next(s2) == 3

def next_(s):
    return Stream(lambda: s[s.i + 1])

class Var:
    name: str
    env: Dict

    def __next__(self):
        return next(self.env[self.name])

env = {}
p = where(env, 'fib',
        fib = fby(0, fby(1, Stream(lambda: env['fib'].vals[-2] + env['fib'].vals[-1]))))
print(next(p))
print(next(p))
print(next(p))
print(next(p))
print(next(p))
print(next(p))
print(next(p))
nodes = Table({'id': [], 'value': []}, columns=['id', 'value'])
edges = Table({'from': [], 'to': []}, columns=['from', 'to'])

class Id(int):
    pass

def node(val):
    global nodes
    i = len(nodes)
    nodes = nodes.append((i, val))
    return Id(i)

def edge(*args):
    global edges
    for a, b in zip(args, args[1:]):
        edges = edges.append((a, b))

def render_graph():
    from graphviz import Digraph
    import os
    dot = Digraph()
    node_names = {}

    for id_, n in nodes.tuples():
        nn = n + f'<{id_}>'
        node_names[id_] = nn
        dot.node(nn)

    for from_, to in edges.tuples():
        dot.edge(node_names[from_], node_names[to])

    dot.render('test', format='png', view=True)

fib = node('fib')

def lift(x):
    if isinstance(x, Id):
        return x
    return node(x)

def fby(first, rest):
    nfirst = lift(first)
    nrest = lift(rest)
    nself = node('fby')
    edge(nfirst, nself, nrest)
    return nself

def add(a, b):
    na = lift(a)
    nb = lift(b)
    nself = node('add')
    edge(na, nself)
    edge(nb, nself)
    return nself

def next_(n):
    nn = lift(n)
    nself = node('next')
    edge(nn, nself)
    return nself

def where(expr, **bindings):
    edge(bindings[list(bindings.keys())[0]], expr) # FIXME

where(fib, fib=fby(0, fby(1, add(fib, next_(fib)))))

render_graph()

M table.py => table.py +3 -0
@@ 50,6 50,9 @@ class Table:
        except ValueError:
            raise AttributeError('No such column', name)

    def __len__(self):
        return len(self.column_data[0])

    def tuples(self) -> Iterator[Tuple]:
        for t in zip(*self.column_data):
            yield t