Non-Deterministic Evaluation In Under 300 Bytes

Michael Hudson mwh21 at cam.ac.uk
Mon Mar 20 20:11:19 EST 2000


I was playing around with Chris Tismer's stackless python today, and
wondering what I could actually use continuations for, so I pulled my
copy of On Lisp off the bookshelf and came up with:

from continuation import caller

def choose(cs):
    if not cs:
        if _p:
            _p.pop()()
        raise "no answers found"
    _p.append( lambda c=cs[1:],k=caller():k(choose(c)) )
    return cs[0]

def amb_eval(f,*a):
    global _p; _p = []
    try:
        return apply(f,a)
    finally:
        _p = []

(that's actually 317 bytes, but if you take the indentation down to 1,
it's about 280).

It can be used like so:

Python 1.5.42 (#1, Mar 19 2000, 15:06:01)  ...
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
>>> import short_amb # I have a more verbose, easier to use version...
>>> def trick(n):
...     x = short_amb.choose(range(2,11,2))
...     y = short_amb.choose(range(1,11))
...     if x + y <> n: short_amb.choose([])
...     return x,y
... 
>>> short_amb.amb_eval(trick,12)
(2, 10)

(the example's from On Lisp).

It's not fast, but I think it's cute, and quite a nice exposition of
just how powerful continuations can be.

Random thoughts:

1) excessive use of side effects in code being non-deterministically
   evaluated *will* make you're head explode.  
2) call-with-current-continuation is a *really bad* interface to the
   continuation world, at least from the point of actually
   understanding the code (I implemented the above by writing a
   call/cc function, transliterating the scheme version Graham
   presents in the book, and then "unwinding" the calls to
   call/cc. The result made more sense then the original - even than
   the scheme!). Chris's approach is better, at least for me.
3) The above does a depth-first search of the solution space, but can
   be made to do breadth first search with the addition of a single
   character ("_p.pop()()" -> "_p.pop(0)()").

Anybody feel like extending the above to unification/resolution and
hence embedding (possibly the slowest implementation the world has
ever seen of) a prolog-style language in Python?  I'd give it a stab,
but I don't know logic programming that well.

i-want-an-iopcc-ly y'rs
M.

-- 
very few people approach me in real life and insist on proving they are
drooling idiots.                         -- Erik Naggum, comp.lang.lisp



More information about the Python-list mailing list