]> hydra-www.ietfng.org Git - dyna2/commitdiff
Use Dyna Boolean type instead of Python's bool. This requires redefining or
authorTim Vieira <tim.f.vieira@gmail.com>
Thu, 11 Jul 2013 15:38:25 +0000 (11:38 -0400)
committerTim Vieira <tim.f.vieira@gmail.com>
Thu, 11 Jul 2013 15:38:25 +0000 (11:38 -0400)
wrapping Python's comparsion (<=, ==), and logical operators (and, or,qq not).

move examples/lists into repl tests.
updated examples/force to use dyna lists
updated some other tests..

13 files changed:
examples/expected/lists.py.out [deleted file]
examples/force.dyna
examples/lists.dyna [deleted file]
src/Dyna/Backend/Python/Backend.hs
src/Dyna/Backend/Python/Selftest.hs
src/Dyna/Backend/Python/aggregator.py
src/Dyna/Backend/Python/chart.py
src/Dyna/Backend/Python/interpreter.py
src/Dyna/Backend/Python/load/tsv.py
src/Dyna/Backend/Python/stdlib.py
src/Dyna/Backend/Python/term.py
src/Dyna/Backend/Python/utils.py
test/repl/list.dynadoc

diff --git a/examples/expected/lists.py.out b/examples/expected/lists.py.out
deleted file mode 100644 (file)
index c678512..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-
-Solution
-========
-a = [1, 2].
-b = true.
-c = true.
-d = false.
-things = [1, [2, 2], [3, 4]].
-thingsbag = [1, 1, 2, "three"].
-thingset = [1, 2, "three"].
-
-d/1
-===
-d(2) = true.
-d(4) = true.
-
-f/1
-===
-f([1, 2]).
-
-foo/1
-=====
-foo("a") = true.
-
-goal/1
-======
-goal([2]) = true.
-
-goo/1
-=====
-goo([1, 2]) = true.
-
index f1845bb24c16d81da401619c661047c2a9636446..2c4abb85017003f6f088cbb2b0157214a6184b83 100644 (file)
@@ -21,7 +21,7 @@ forceY(V,T) += f(U,V,T) * (y(U,T) - y(V,T)).
 
 % Constants
 a := 0.15.
-niter := 200.
+niter := 20.
 edgelen := 4.0.   % "the unit edge length"
 
 % should `a` be negative?
@@ -35,8 +35,8 @@ edge(A,B) := edge(B,A).
 node(U) :- true for _ is edge(U,_).
 node(U) :- true for _ is edge(_,U).
 
-% pack x and y into a tuple
-pos(U,T) := tuple(x(U, T), y(U, T)).
+% pack x and y into a list
+pos(U,T) := [x(U, T), y(U, T)].
 
 % visualization
 frame(T, &text(Name, pos(Name, T))) := true for node(Name).
diff --git a/examples/lists.dyna b/examples/lists.dyna
deleted file mode 100644 (file)
index 5e4dd94..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-f([1,2]).
-
-a := [1,2].
-
-goal(X) := f([1|X]).
-
-% structured term, sould be true
-b := &f("a") in [1,2,&f("a"),3].
-
-% should be true
-c := 2 in [1,2,3].
-
-% should be false
-d := 4 in [1,2,3].
-
-% simpler iteration of a complex list
-things set= X for X in [1,[2,2],[3,4]].
-
-% unpack structure requiring a check
-d(&X) := true for [X,X] in [1,[2,2],[3,4],[4,4]].
-
-% these two examples should an interesting behavior
-foo(A) := true for &f(A) in [1,2,&f("a"),3].
-
-% this one checks if the value of f(A) is in the list, (note: 1 == True, in python).
-goo(A) := true for f(A) in [1,2,&f("a"),3].
-
-thingsbag bag= "three".
-thingsbag bag= 1.
-thingsbag bag= 1.
-thingsbag bag= 2.
-
-thingset set= "three".
-thingset set= 1.
-thingset set= 1.
-thingset set= 2.
\ No newline at end of file
index 74419afd37cbfd8304ff0ef82e38099284363107..7d19c29cbacfe2f987d1a448b83e258fd819f6e3 100644 (file)
@@ -154,13 +154,10 @@ constants = go
  where
   go ("-",1)     = Just $ PDBS $ call "-" []
   go ("^",2)     = Just $ PDBS $ infixOp "^"
-  go ("|",2)     = Just $ PDBS $ infixOp "|"
   go ("-",2)     = Just $ PDBS $ infixOp "-"
   go ("/",2)     = Just $ PDBS $ infixOp "/"
   go ("*",2)     = Just $ PDBS $ infixOp "*"
   go ("**",2)    = Just $ PDBS $ infixOp "**"
-  go ("&",2)     = Just $ PDBS $ infixOp "&"
-  go ("%",2)     = Just $ PDBS $ infixOp "%"
   go ("+",2)     = Just $ PDBS $ infixOp "+"
 
   go ("mod",2)   = Just $ PDBS $ infixOp "%"
@@ -168,39 +165,36 @@ constants = go
   go ("log",_)   = Just $ PDBS $ call "log" []
   go ("exp",1)   = Just $ PDBS $ call "exp" []
   go ("sqrt",1)    = Just $ PDBS $ call "sqrt" []
-  go ("getattr",_) = Just $ PDBS $ call "getattr" []
+
+
   go ("uniform",_) = Just $ PDBS $ call "uniform" []
 
+  go ("pycall",_)  = Just $ PDBS $ call "pycall" []
   go ("split",_)   = Just $ PDBS $ call "split" []
   go ("float",_)   = Just $ PDBS $ call "float" []
   go ("int",_)     = Just $ PDBS $ call "int" []
-  go ("pycall",_)  = Just $ PDBS $ call "pycall" []
-
   go ("range",_)  = Just $ PDBS $ call "range" []
 
-  go ("in",2)    = Just $ PDBS $ call "in_list" []
-
-  go ("<=",2)    = Just $ PDBS $ infixOp "<="
-  go ("<",2)     = Just $ PDBS $ infixOp "<"
-  go ("=",2)     = Just $ PDBS $ call "equals" []
-  go ("==",2)    = Just $ PDBS $ call "equals" []
-  go (">=",2)    = Just $ PDBS $ infixOp ">="
-  go (">",2)     = Just $ PDBS $ infixOp ">"
-  go ("!=",2)    = Just $ PDBS $ infixOp "!="
+  go ("<=",2)    = Just $ PDBS $ call "lte" []
+  go ("<",2)     = Just $ PDBS $ call "lt" []
+  go ("=",2)     = Just $ PDBS $ call "eq" []
+  go ("==",2)    = Just $ PDBS $ call "eq" []
+  go (">=",2)    = Just $ PDBS $ call "gte" []
+  go (">",2)     = Just $ PDBS $ call "gt" []
+  go ("!=",2)    = Just $ PDBS $ call "not_eq" []
 
-  go ("and",2)   = Just $ PDBS $ infixOp "and"
-  go ("or",2)    = Just $ PDBS $ infixOp "or"
+  go ("|",2)     = Just $ PDBS $ call "or_" []
+  go ("&",2)     = Just $ PDBS $ call "and_" []
+  go ("!",1)     = Just $ PDBS $ call "not_" []
 
-  go ("true",0)  = Just $ PDBS $ nullary "True"
-  go ("false",0) = Just $ PDBS $ nullary "False"
-  go ("null",0)  = Just $ PDBS $ nullary "None"
+  go ("true",0)  = Just $ PDBS $ nullary "true"
+  go ("false",0) = Just $ PDBS $ nullary "false"
+  go ("null",0)  = Just $ PDBS $ nullary "null"
 
-  go ("!",1)     = Just $ PDBS $ call "not" []
-  go ("not",1)   = Just $ PDBS $ call "not" []
-
-  go ("eval",1)  = Just $ PDBS $ call "None;exec " []
-  go ("tuple",_) = Just $ PDBS $ call "" []
+  --go ("eval",1)  = Just $ PDBS $ call "None;exec " []
+  --go ("tuple",_) = Just $ PDBS $ call "" []
 
+  go ("in",2)    = Just $ PDBS $ call "in_list" []
   go ("nil",0)   = Just $ PDBS $ call "build" ["nil/0"]
   go ("cons",2)  = Just $ PDBS $ call "build" ["cons/2"]
 
@@ -252,8 +246,8 @@ piterate vs = if length vs == 0 then "_"
 pdope_ :: S.Set DFunctAr -> DOpAMine PyDopeBS -> State Int (Doc e)
 pdope_ _ (OPIndr _ _)   = dynacSorry "indirect evaluation not implemented"
 pdope_ _ (OPAsgn v val) = return $ pretty v <+> equals <+> pretty val
-pdope_ _ (OPCheq v val) = return $ "if not equals(" <> pretty v <> ", " <> pretty val <> "): continue"
-pdope_ _ (OPCkne v val) = return $ "if equals(" <> pretty v <> ", " <> pretty val <> "): continue"
+pdope_ _ (OPCheq v val) = return $ "if not eq(" <> pretty v <> ", " <> pretty val <> "): continue"
+pdope_ _ (OPCkne v val) = return $ "if eq(" <> pretty v <> ", " <> pretty val <> "): continue"
 pdope_ _ (OPPeel vs i f _) = return $
     "try:" `above` (indent 4 $
            tupledOrUnderscore vs
index abd4a3fbcc80c543d3f75fc42fb40d9edaf0c693..d2f65cbfa67bb4514cc0b31cbb4949a97064ddb0 100644 (file)
@@ -77,7 +77,7 @@ mkExample name =
 test_End_To_End :: [Test]
 test_End_To_End = map mkExample
   [ "simple", "equalities", "fib-limit", "dijkstra", "papa2", "matrixops"
-  , "factorial-bc", "geom", "lists", "dijkstra-backpointers" ]
+  , "factorial-bc", "geom", "dijkstra-backpointers" ]
 
 --test_REPL :: [Test]
 --test_REPL = map (\n -> testProgramRuns n ("./test/repl/"++n) [])
index ee99ab31becfa857309baff33a50f6481223cb01..f393bd9649288fc7bfff73f3adac5b31cd252988 100644 (file)
@@ -7,7 +7,7 @@ from __future__ import division
 
 import operator
 from collections import Counter
-from utils import drepr, _repr, user_vars
+from utils import drepr, _repr, user_vars, isbool, true, false
 from errors import AggregatorError
 
 
@@ -142,10 +142,16 @@ class or_equals(BAggregator):
         s = [x for x, m in self.iteritems() if m > 0]
         if len(s):
             for val in s:
-                if val is not True and val is not False:
+                if not isbool(val):
                     raise TypeError('%s is not Boolean.' % _repr(val))
 
-            return reduce(lambda x,y: x or y, s)
+            # TODO: can short circuit as soon as we get a true... but above we
+            # check the types.. so we don't get the benefit.
+            for val in s:
+                if val is true:
+                    return true
+            return false
+
 
 
 class and_equals(BAggregator):
@@ -153,10 +159,16 @@ class and_equals(BAggregator):
         s = [x for x, m in self.iteritems() if m > 0]
         if len(s):
             for val in s:
-                if val is not True and val is not False:
+                if not isbool(val):
                     raise TypeError('%s is not Boolean.' % _repr(val))
-            return reduce(lambda x,y: x and y, s)
 
+            # TODO: can short circuit as soon as we get a false. but above we
+            # check the types.. so we don't get the benfit
+            for val in s:
+                if val is false:
+                    return false
+            return true
+            
 
 class set_equals(BAggregator):
     def fold(self):
index 8e8df05b7e6973a191b3473afec6b09be899c599..97f4c58f9922605f293295566af81e523b8e695e 100644 (file)
@@ -1,8 +1,8 @@
 from collections import defaultdict
 from aggregator import aggregator
 from term import Term
-from utils import _repr
-from stdlib import equals
+from utils import _repr, true
+
 
 class Chart(object):
 
@@ -24,10 +24,10 @@ class Chart(object):
         heading = [self.name, '='*len(self.name)]
 
         # special handing or-equals aggregators -- only list true facts (and errors)
-        if self.agg_name == ':-' or self.agg_name == '|=':
+        if self.agg_name == ':-':
             lines = []
             for term in sorted(rows):
-                if term.value is True:
+                if term.value is true:
                     lines.append('%s.' % _repr(term))
                 elif term.value:  # e.g. $error
                     lines.append('%s = %s.' % (_repr(term), _repr(term.value)))
@@ -80,7 +80,7 @@ class Chart(object):
                     yield term, term.args, term.value
         else:
             for term in candidates:
-                if equals(term.value, val):
+                if term.value == val:
                     yield term, term.args, term.value
 
     def insert(self, args):        # TODO: rename
index ea2b06ee69c006844b2387a9fff1c890c47344ca..2a3da45a683cf44cbdf18c17d5dd3c31e8610b95 100644 (file)
@@ -81,7 +81,8 @@ import load, post
 from term import Term, Cons, Nil, MapsTo
 from chart import Chart
 from utils import ip, red, green, blue, magenta, yellow, parse_attrs, \
-    ddict, dynac, read_anf, strip_comments, _repr, hide_ugly_filename
+    ddict, dynac, read_anf, strip_comments, _repr, hide_ugly_filename, \
+    true, false
 
 from prioritydict import prioritydict
 from config import dotdynadir
@@ -265,16 +266,15 @@ 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':
-            return True
+            return true
         if fn == 'false/0':
-            return False
+            return false
         if fn == 'cons/2':
             return Cons(*args)
         if fn == 'nil/0':
             return Nil
         if fn == '->/2':
             return MapsTo(*args)
-
         if fn == '$key/1':
             self.new_fn(fn, '=')
 
@@ -295,7 +295,7 @@ class Interpreter(object):
 
         # remove $rule
         if hasattr(rule, 'item'):
-            self.delete_emit(rule.item, True, ruleix=None, variables=None)
+            self.delete_emit(rule.item, true, ruleix=None, variables=None)
 
         if rule.init is not None:
             # remove update handlers
@@ -387,6 +387,9 @@ class Interpreter(object):
                 # Thus, we can skip the delete-updates.
                 self.update_dispatcher(item, was, delete=True)
 
+
+            assert now is not True or now is not False  # invalid dyna types.
+
             item.value = now
 
             if now is not None:
@@ -449,6 +452,7 @@ class Interpreter(object):
             h(*args, emit=_emit)
 
         head.value = head.aggregator.fold()
+
         return head.value
 
     def new_query(self, fn, ruleix, handler):
@@ -548,7 +552,7 @@ class Interpreter(object):
             if interp.agg_name[fn] is None:
                 interp.new_fn(fn, ':=')
             item = interp.build(fn, ix, *a)
-            interp.emit(item, True, ruleix=None, variables=None, delete=False)
+            interp.emit(item, true, ruleix=None, variables=None, delete=False)
             return item
         for i in new_rules:
             r = self.rules[i]
@@ -594,10 +598,10 @@ def peel(fn, item):
     and constants (possibly an empty tuple).
     """
     if fn == "true/0":
-        assert item is True
+        assert item is true
         return
     if fn == "false/0":
-        assert item is False
+        assert item is false
         return
     assert isinstance(item, Term)
     assert item.fn == fn
index e94d4507b2d86c8a0a1e49605effc9514a485d9c..fd68ad3104008d89e49c3da180e572d34eea3f68 100644 (file)
@@ -4,6 +4,7 @@ TODO: option for strict number of columns.
 """
 
 import re
+from utils import true
 
 class tsv(object):
     """
@@ -37,10 +38,10 @@ class tsv(object):
             fn = '%s/%s' % (name, len(a))
 
             if interp.agg_name[fn] is None:
-                interp.new_fn(fn, ':=')
+                interp.new_fn(fn, ':-')
 
             interp.emit(interp.build(fn, *a),
-                        True,
+                        true,
                         ruleix=None,
                         variables=None,
                         delete=False)
index 832765228dba7afae6a19e09dad7f08e591d5f93..1b740cd1b7b02ba90657bd74f09b4acb3e794b0a 100644 (file)
@@ -1,42 +1,76 @@
 import re
 from term import Term, Cons, Nil, MapsTo
 from collections import Counter
-from utils import pretty, pretty_print
-
-
+from utils import pretty, pretty_print, true, false, null, isbool
 from math import log, exp, sqrt
 from random import random as _random
+
 def uniform(a=0, b=1):
     return _random() * (b - a) + a
 
 
-def equals(x,y):
+def or_(x, y):
+    if not (isbool(x) and isbool(y)):
+        raise TypeError('')
+    return todyna(x or y)
+
+def and_(x, y):
+    if not (isbool(x) and isbool(y)):
+        raise TypeError('')
+    return todyna(x and y)
+
+def not_(x):
+    if not isbool(x):
+        raise TypeError('')
+    if x:
+        return false
+    else:
+        return true
+
+def gt(x, y):
+    return todyna(x > y)
+
+def gte(x, y):
+    return todyna(x >= y)
+
+def lt(x, y):
+    return todyna(x < y)
+
+def lte(x, y):
+    return todyna(x <= y)
+
+def eq(x,y):
     """
     My work around for discrepency in bool equality True==1 and False==0.
 
-    >>> equals(True, 1)
-    False
+    >>> eq(true, 1)
+    false
 
-    >>> equals(1, 1.0)
-    True
+    >>> eq(1, 1.0)
+    true
     """
-    if isinstance(x, bool) or isinstance(y, bool):
-        return type(x) == type(y) and x == y
-    else:
-        return x == y
+    return todyna(x == y)
 
+def not_eq(x, y):
+    if x != y:
+        return true
+    else:
+        return false
 
 _range = range
 def range(*x):
     return todyna(_range(*x))
 
+
 def split(s, delim='\s+'):
-    return todynalist(re.split(delim, s))
+    return todyna(re.split(delim, s))
+
 
 def crash():
     class Crasher(Exception): pass
     raise Crasher('Hey, you asked for it!')
 
+
 def pycall(name, *args):
     """
     Temporary foreign function interface - call Python functions from dyna!
@@ -47,22 +81,14 @@ def pycall(name, *args):
 
 
 def topython(x):
-    #if isinstance(x, AList) or x is Nil:
-    #    return {topython(k): topython(v) for k,v in x.aslist}
-    if isinstance(x, Cons) or x is Nil:
-        return [topython(y) for y in x.aslist]
-    return x
-
-def todynalist(x):    # TODO: get rid of this.
-    return todyna(x)
 
+    if islist(x):
+        return [topython(y) for y in x.aslist]
 
-def getkey(m, k):
-    return m[k]
+    elif isinstance(x, MapsTo):
+        return tuple(x.args)
 
-def setkey(m, k, v):
-    m[k] = v
-    return m
+    return x
 
 
 def todyna(x):
@@ -72,11 +98,13 @@ def todyna(x):
         x.sort()
         return todyna(x)
 
+    elif x is True:
+        return true
+
+    elif x is False:
+        return false
+
     elif isinstance(x, dict):
-        #c = Nil
-        #for k,v in x.items():
-        #    c = AList(todyna([k,v]), c)
-        #return c
         return todyna([MapsTo(k,v) for k,v in x.items()])
 
     elif isinstance(x, (list, tuple)):
@@ -85,22 +113,39 @@ def todyna(x):
             c = Cons(todyna(y), c)
         return c
     else:
+
         return x
 
 
 def get(x, i):
     return x[i]
 
+
+def getkey(m, k):
+    return m[k]
+
+
+def setkey(m, k, v):
+    m[k] = v
+    return m
+
+
+def islist(x):
+    return isinstance(x, Cons) or x is Nil
+
+
 def iter_cons(x):
-    if not (isinstance(x, Cons) or x is Nil):
-        raise TypeError("Attemping to iterate something which isn't a list.")
+    if not islist(x):
+        raise TypeError("Attemping to iterate something which isn't a list. %r" % (x,))
     return x.like_chart()
 
+
 def in_list(x, a):
-    if not (isinstance(a, Cons) or a is Nil):
-        raise TypeError("Attemping to iterate something which isn't a list.")
+    if not islist(a):
+        raise TypeError("Attemping to iterate something which isn't a list. %r" % (a,))
     return x in a.aslist
 
+
 # should probably be done with memoized backchaining...
 def read_lines(filename):
     with file(filename) as f:
index f8b1e39fb23a74d7d376628b5524c1924c9d59fe..14a5cf181d089a9c35ec1da0b9a49b931c3d112c 100644 (file)
@@ -1,5 +1,5 @@
 from errors import notimplemented
-from utils import _repr
+from utils import _repr, true, false
 from aggregator import NoAggregator
 
 
@@ -70,7 +70,10 @@ class Cons(Term):
         return '[%s]' % (', '.join(map(_repr, self.aslist)))
 
     def __contains__(self, x):
-        return x in self.aslist
+        if x in self.aslist:
+            return true
+        else:
+            return false
 
     def like_chart(self):
         for a in self.aslist:
@@ -109,7 +112,7 @@ class _Nil(Term):
         return '[]'
 
     def __contains__(self, x):
-        return False
+        return false
 
     def like_chart(self):
         return iter([])
index affd0bce80445b90da4d58680f663bc30cd221e7..b2e813021194b309ad60b36ed4c806c346e41a14 100644 (file)
@@ -7,11 +7,38 @@ from collections import namedtuple
 from cStringIO import StringIO
 
 
+
+class _true(object):
+    def __nonzero__(self):
+        return True
+    def __repr__(self):
+        return 'true'
+
+class _false(object):
+    def __nonzero__(self):
+        return False
+    def __repr__(self):
+        return 'false'
+
+true = _true()
+false = _false()
+null = None
+
+def isbool(x):
+    return x is true or x is false
+
+
+
+
 def _repr(x):
+
+# TODO: this assertion should eventually hold.
+#    assert x is not True and x is not False, x
     if x is True:
         return 'true'
     elif x is False:
         return 'false'
+
     elif x is None:
         return 'null'
     elif isinstance(x, basestring):
index ebdcc22afc17c85a9081211a1caeac53c9811a04..16b2b88ce6e4cdcc06cd5d5eb8e50e906bdeb3cb 100644 (file)
@@ -83,24 +83,32 @@ Changes
 d(2) = true.
 d(4) = true.
 
-% quote is important! or else we enumerate everything!
-> foo(A) := true for &bar(A) in [1,2,&bar("a"),3].
-|
-| bar("int") = 1.
+
+% let's look at a the difference between Booleans and integers
+> bar("int") = 1.
 | bar("bool") = true.
-| bar("spaz") = 2.
-|
-| goo(A) := true for bar(A) in [true,2,&bar("a"),3].
+| bar("two") = 2.
 
 Changes
 =======
 bar("bool") = true.
 bar("int") = 1.
-bar("spaz") = 2.
+bar("two") = 2.
+
+% quote is important! or else we enumerate everything!
+> foo(A) := true for &bar(A) in [1,2,&bar("a"),3].
+
+Changes
+=======
 foo("a") = true.
+
+% if you don't quote bar(A) drives the querym checking membership in the list.
+> goo(A) := true for bar(A) in [true,2,&bar("a")].
+
+Changes
+=======
 goo("bool") = true.
-goo("int") = true.                 % TODO: this should't appear in the results (XREF:bool)
-goo("spaz") = true.
+goo("two") = true.
 
 
 % unfortunately 1 == true and 0 == false in python so the following is true
@@ -108,7 +116,7 @@ goo("spaz") = true.
 
 Changes
 =======
-testbool = true.                  % TODO: XREF:bool
+testbool = false.
 
 
 % fun with set= at bag=
@@ -126,5 +134,5 @@ testbool = true.                  % TODO: XREF:bool
 
 Changes
 =======
-thingsbag = [1, 1, 1, 2, "three"].
-thingset = [1, 2, "three"].
+thingsbag = [1, 1, 2, "three", true].
+thingset = [1, 2, true, "three"].