From: Tim Vieira Date: Fri, 28 Jun 2013 19:38:19 +0000 (-0400) Subject: pretty print lists, which are still cons/nil under the hood. X-Git-Url: https://hydra-www.ietfng.org/gitweb/?a=commitdiff_plain;h=b157020e234a7787b004eb83e3ad724034651b5d;p=dyna2 pretty print lists, which are still cons/nil under the hood. Moved some library functions in into stdlib.py Moved attempt at unifiction into it's own file... it will probably be deleted entirely in favor of something else (it's unused at the moment). --- diff --git a/src/Dyna/Backend/Python/chart.py b/src/Dyna/Backend/Python/chart.py index 7b90ad6..0b14aeb 100644 --- a/src/Dyna/Backend/Python/chart.py +++ b/src/Dyna/Backend/Python/chart.py @@ -1,6 +1,7 @@ from collections import defaultdict from defn import aggregator -from term import Term, _repr +from term import Term +from utils import _repr class Chart(object): diff --git a/src/Dyna/Backend/Python/interpreter.py b/src/Dyna/Backend/Python/interpreter.py index f55ddbb..d717a5a 100644 --- a/src/Dyna/Backend/Python/interpreter.py +++ b/src/Dyna/Backend/Python/interpreter.py @@ -196,40 +196,18 @@ from path import path import load, post -from chart import Chart, Term, _repr +from term import Term, Cons, Nil +from chart import Chart from defn import aggregator from utils import ip, red, green, blue, magenta, yellow, parse_attrs, \ - ddict, dynac, read_anf, strip_comments + ddict, dynac, read_anf, strip_comments, _repr from prioritydict import prioritydict from config import dotdynadir from errors import notimplemented, enable_crash_handler, \ DynaInitializerException, DynaCompilerError -try: - from numpy import log, exp, sqrt - from numpy.random import uniform -except ImportError: # XXX: should probably issue a warning. - from math import log, exp, sqrt - from random import random as _random - def uniform(a=0, b=1): - return _random() * (b - a) + a - -import re -def split(s, delim='\s+'): - return re.split(delim, s) - -# used as a work around to bring arbitrary python functions into dyna -def pycall(name, *args): - x = eval(name)(*args) - if isinstance(x, list): - return todynalist(x) - return x - -def todynalist(x): - if not x: - return Term('nil/0', ()) - return Term('cons/2', (x[0], todynalist(x[1:]))) +from stdlib import * class Rule(object): @@ -362,11 +340,17 @@ class Interpreter(object): def build(self, fn, *args): # TODO: codegen should handle true/0 is True and false/0 is False - if fn == "true/0": + if fn == 'true/0': return True - if fn == "false/0": + if fn == 'false/0': return False + if fn == 'cons/2': + return Cons(*args) + if fn == 'nil/0': + return Nil + + # FIXME: if fn not in self.agg_name: # item has no aggregator (e.g purely structural stuff) -- what diff --git a/src/Dyna/Backend/Python/stdlib.py b/src/Dyna/Backend/Python/stdlib.py new file mode 100644 index 0000000..1da99ad --- /dev/null +++ b/src/Dyna/Backend/Python/stdlib.py @@ -0,0 +1,26 @@ +from term import Term, Cons, Nil + +try: + from numpy import log, exp, sqrt + from numpy.random import uniform +except ImportError: # XXX: should probably issue a warning. + from math import log, exp, sqrt + from random import random as _random + def uniform(a=0, b=1): + return _random() * (b - a) + a + +import re +def split(s, delim='\s+'): + return re.split(delim, s) + +# used as a work around to bring arbitrary python functions into dyna +def pycall(name, *args): + x = eval(name)(*args) + if isinstance(x, list): + return todynalist(x) + return x + +def todynalist(x): + if not x: + return Nil + return Cons(x[0], todynalist(x[1:])) diff --git a/src/Dyna/Backend/Python/term.py b/src/Dyna/Backend/Python/term.py index 79b96b2..f0846a3 100644 --- a/src/Dyna/Backend/Python/term.py +++ b/src/Dyna/Backend/Python/term.py @@ -45,191 +45,29 @@ class Term(object): __add__ = __sub__ = __mul__ = notimplemented -# def subst(self, v): -# if self in v: -# return v[self] -# # TODO: this should go thru the Chart -# return Term(self.fn, tuple(x if isconst(x) else x.subst(v) for x in self.args)) - - -def isconst(x): - return not isinstance(x, (Variable, Term)) - - - -class Variable(object): - - def __init__(self, name): - self.fn = name - self._val = None - - @property - def value(self): - return self.root._val - - @property - def root(self): - if isinstance(self._val, Variable): - return self._val.root - else: - return self - - @value.setter - def value(self, v): - self._val = v - -# def __repr__(self, other): -# if self.value is None: -# return self.fn + '=' + self.root.fn -# else: -# return _repr(self.value) -# return '%s=%s' % (self.fn, _repr(self.value)) +class Cons(Term): + def __init__(self, head, tail): + self.head = head + self.tail = tail + assert isinstance(tail, (Cons, _Nil)), tail + Term.__init__(self, 'cons/2', (head, tail)) + def tolist(self): + return [self.head] + self.tail.tolist() def __repr__(self): - if self.value is None: - return self.root.fn - else: - return _repr(self.value) - + return repr(self.tolist()) def __eq__(self, other): - if isinstance(other, Variable): - - if self.root is other.root: - return True - - if self.value is not None: - return other.value == self.value - + try: + return self.tolist() == other.tolist() + except AttributeError: return False - else: - return other == self.value - -# def subst(self, v): -# if self in v: -# return v[self] -# return self - - -def extend(v, x, t): - """ - Extend valuation v with v[x] = t - """ - v1 = v.copy() - v1[x] = t -# x.value = t - return v1 - - -def occurs_check(v, t): - """ - Return true if variable ``v`` occurs anywhere in term ``t``." - - >>> [f,g,h,X,Y,Z] = map(symbol, ['f','g','h','X','Y','Z']) - - >>> occurs_check(X, f(g(h(X,Y),X))) - True - - >>> occurs_check(Z, f(g(h(X,Y),X))) - False - - """ - if v == t: - return True - elif isinstance(t, Term): - return any(occurs_check(v, x) for x in t.args) - return False - - -def unify_var(x, t, v): - """ - Test if v can be extended with v[x] = t; - In that case return the extention - Else return None - """ - if x in v: - return _unify(v[x], t, v) - elif occurs_check(x, t): - return None - else: - return extend(v, x, t) - - -def unify(x,y): - return _unify(x,y,{}) - - -def _unify(x,y,v): - """ - Find one valuation extending v and unifying x with y - """ - if v is None: - return None - elif x == y: - return v - elif isinstance(x, Variable): - return unify_var(x, y, v) - elif isinstance(y, Variable): - return unify_var(y, x, v) - elif isinstance(x, Term) and isinstance(y, Term) and x.fn == y.fn: - if len(x.args) == len(y.args): - for a, b in zip(x.args, y.args): - v = _unify(a, b, v) - return v - - -def symbol(name): - if name[0].isupper(): - return Variable(name) - - class Symbol(object): - def __init__(self, name): - self.name = name - def __call__(self, *args): - return Term('%s/%s' % (self.name, len(args)), args) - def __str__(self): - return self.name - - return Symbol(name) - +class _Nil(Term): + def __init__(self): + Term.__init__(self, 'nil/0', ()) + def tolist(self): + return [] + def __repr__(self): + return '[]' -#if __name__ == '__main__': -# -# [f,g,h] = map(symbol, ['f','g','h']) -# vs = [X,Y,Z] = map(symbol, ['X','Y','Z']) -# -# def test(a, b): -# for v in vs: -# v.value = None -# -# print -# print 'unify %s and %s' % (a,b) -# s = unify(a, b) -# print '->', s -# if s is None: -# return -# -# # apply new bindings -# for v, now in s.iteritems(): -# print '%s [was: %r, now: %r]' % (v, v.value, now) -# v.value = now -# -# print a, b -# assert a == b -# assert repr(a) == repr(b), [a,b] -# -# for v in vs: -# v.value = None -# -# test(f(X), f(g(h(X,Y),X))) -# test(f(X), f(g(h(Z),"foo"))) -# test(f(X, Y), f("cat", 123)) -# test(f(X), f(X)) -# test(f(X), f(Y)) -# test("abc", "abc") -# -# Z.value = 3 -# Y.value = Z -# X.value = Y -# print [X,Y,Z] -# assert X.value == Y.value == Z.value == 3 +Nil = _Nil() diff --git a/src/Dyna/Backend/Python/unify.py b/src/Dyna/Backend/Python/unify.py new file mode 100644 index 0000000..c5f6f6f --- /dev/null +++ b/src/Dyna/Backend/Python/unify.py @@ -0,0 +1,183 @@ +from term import Term +from utils import _repr + +def isconst(x): + return not isinstance(x, (Variable, Term)) + + +class Variable(object): + + def __init__(self, name): + self.fn = name + self._val = None + + @property + def value(self): + return self.root._val + + @property + def root(self): + if isinstance(self._val, Variable): + return self._val.root + else: + return self + + @value.setter + def value(self, v): + self._val = v + +# def __repr__(self, other): +# if self.value is None: +# return self.fn + '=' + self.root.fn +# else: +# return _repr(self.value) +# return '%s=%s' % (self.fn, _repr(self.value)) + + def __repr__(self): + if self.value is None: + return self.root.fn + else: + return _repr(self.value) + + def __eq__(self, other): + if isinstance(other, Variable): + + if self.root is other.root: + return True + + if self.value is not None: + return other.value == self.value + + return False + + else: + return other == self.value + +# def subst(self, v): +# if self in v: +# return v[self] +# return self + + +def extend(v, x, t): + """ + Extend valuation v with v[x] = t + """ + v1 = v.copy() + v1[x] = t +# x.value = t + return v1 + + +def occurs_check(v, t): + """ + Return true if variable ``v`` occurs anywhere in term ``t``." + + >>> [f,g,h,X,Y,Z] = map(symbol, ['f','g','h','X','Y','Z']) + + >>> occurs_check(X, f(g(h(X,Y),X))) + True + + >>> occurs_check(Z, f(g(h(X,Y),X))) + False + + """ + if v == t: + return True + elif isinstance(t, Term): + return any(occurs_check(v, x) for x in t.args) + return False + + +def unify_var(x, t, v): + """ + Test if v can be extended with v[x] = t; + In that case return the extention + Else return None + """ + if x in v: + return _unify(v[x], t, v) + elif occurs_check(x, t): + return None + else: + return extend(v, x, t) + + +def unify(x,y): + return _unify(x,y,{}) + + +def _unify(x,y,v): + """ + Find one valuation extending v and unifying x with y + """ + if v is None: + return None + elif x == y: + return v + elif isinstance(x, Variable): + return unify_var(x, y, v) + elif isinstance(y, Variable): + return unify_var(y, x, v) + elif isinstance(x, Term) and isinstance(y, Term) and x.fn == y.fn: + if len(x.args) == len(y.args): + for a, b in zip(x.args, y.args): + v = _unify(a, b, v) + return v + + +def symbol(name): + if name[0].isupper(): + return Variable(name) + + class Symbol(object): + def __init__(self, name): + self.name = name + def __call__(self, *args): + return Term('%s/%s' % (self.name, len(args)), args) + def __str__(self): + return self.name + + return Symbol(name) + + +#if __name__ == '__main__': +# +# [f,g,h] = map(symbol, ['f','g','h']) +# vs = [X,Y,Z] = map(symbol, ['X','Y','Z']) +# +# def test(a, b): +# for v in vs: +# v.value = None +# +# print +# print 'unify %s and %s' % (a,b) +# s = unify(a, b) +# print '->', s +# if s is None: +# return +# +# # apply new bindings +# for v, now in s.iteritems(): +# print '%s [was: %r, now: %r]' % (v, v.value, now) +# v.value = now +# +# print a, b +# assert a == b +# assert repr(a) == repr(b), [a,b] +# +# for v in vs: +# v.value = None +# +# test(f(X), f(g(h(X,Y),X))) +# test(f(X), f(g(h(Z),"foo"))) +# test(f(X, Y), f("cat", 123)) +# test(f(X), f(X)) +# test(f(X), f(Y)) +# test("abc", "abc") +# +# Z.value = 3 +# Y.value = Z +# X.value = Y +# print [X,Y,Z] +# assert X.value == Y.value == Z.value == 3 diff --git a/test/repl/load.dyna b/test/repl/load.dyna index 42bd9e6..b933930 100644 --- a/test/repl/load.dyna +++ b/test/repl/load.dyna @@ -1,5 +1,8 @@ % accompanies load.bash +:- dispos &cons(&,&). +:- dispos &nil. + % binary rules rewrite(X, Y, Z) := rules_tsv(Linenum, Cost, X, R),