98 KiB
98 KiB
In [1]:
def poswrd(s, e, d):
return rolldown(*swap(*pop(s, e, d)))In [2]:
def poswrd(stack):
(_, (a, (b, (c, stack)))) = stack
return (c, (b, (a, stack)))In [3]:
def F(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
return (d, (c, S0)), stackIn [4]:
roll_dn = (1, 2, 3), (2, 3, 1)
pop = (1,), ()
swap = (1, 2), (2, 1)In [5]:
def compose(f, g):
(f_in, f_out), (g_in, g_out) = f, g
# First rule.
#
# (a -- b) (-- d)
# ---------------------
# (a -- b d)
if not g_in:
fg_in, fg_out = f_in, f_out + g_out
# Second rule.
#
# (a --) (c -- d)
# ---------------------
# (c a -- d)
elif not f_out:
fg_in, fg_out = g_in + f_in, g_out
else: # Unify, update, recur.
fo, gi = f_out[-1], g_in[-1]
s = unify(gi, fo)
if s == False: # s can also be the empty dict, which is ok.
raise TypeError('Cannot unify %r and %r.' % (fo, gi))
f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out)
if s: f_g = update(s, f_g)
fg_in, fg_out = compose(*f_g)
return fg_in, fg_outIn [6]:
def unify(u, v, s=None):
if s is None:
s = {}
if isinstance(u, int):
s[u] = v
elif isinstance(v, int):
s[v] = u
else:
s = False
return sIn [7]:
def update(s, term):
if not isinstance(term, tuple):
return s.get(term, term)
return tuple(update(s, inner) for inner in term)In [8]:
def relabel(left, right):
return left, _1000(right)
def _1000(right):
if not isinstance(right, tuple):
return 1000 + right
return tuple(_1000(n) for n in right)
relabel(pop, swap)Out [8]:
(((1,), ()), ((1001, 1002), (1002, 1001)))
In [9]:
def delabel(f):
s = {u: i for i, u in enumerate(sorted(_unique(f)))}
return update(s, f)
def _unique(f, seen=None):
if seen is None:
seen = set()
if not isinstance(f, tuple):
seen.add(f)
else:
for inner in f:
_unique(inner, seen)
return seen
delabel(relabel(pop, swap))Out [9]:
(((0,), ()), ((1, 2), (2, 1)))
In [10]:
def C(f, g):
f, g = relabel(f, g)
fg = compose(f, g)
return delabel(fg)In [11]:
C(pop, swap)Out [11]:
((1, 2, 0), (2, 1))
In [12]:
C(C(pop, swap), roll_dn)Out [12]:
((3, 1, 2, 0), (2, 1, 3))
In [13]:
C(swap, roll_dn)Out [13]:
((2, 0, 1), (1, 0, 2))
In [14]:
C(pop, C(swap, roll_dn))Out [14]:
((3, 1, 2, 0), (2, 1, 3))
In [15]:
poswrd = reduce(C, (pop, swap, roll_dn))
poswrdOut [15]:
((3, 1, 2, 0), (2, 1, 3))
In [16]:
rest = ((1, 2),), (2,)
cons = (1, 2), ((1, 2),)In [17]:
C(poswrd, rest)Out [17]:
(((3, 4), 1, 2, 0), (2, 1, 4))
In [18]:
F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
FOut [18]:
(((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),))
In [19]:
uncons = ((1, 2),), (1, 2)In [20]:
try:
C(cons, uncons)
except Exception, e:
print eCannot unify (1, 2) and (1001, 1002).
In [21]:
def unify(u, v, s=None):
if s is None:
s = {}
elif s:
u = update(s, u)
v = update(s, v)
if isinstance(u, int):
s[u] = v
elif isinstance(v, int):
s[v] = u
elif isinstance(u, tuple) and isinstance(v, tuple):
if len(u) != 2 or len(v) != 2:
# Not a type error, caller passed in a bad value.
raise ValueError(repr((u, v))) # FIXME this message sucks.
(a, b), (c, d) = u, v
s = unify(a, c, s)
if s != False:
s = unify(b, d, s)
else:
s = False
return sIn [22]:
C(cons, uncons)Out [22]:
((0, 1), (0, 1))
In [23]:
def F_python(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
return (d, (c, S0)), stackIn [24]:
F[0]Out [24]:
((3, (4, 5)), 1, 2, 0)
In [25]:
F[1]Out [25]:
((2, (1, 5)),)
In [26]:
from collections import defaultdict
from joy.parser import Symbol
def _names_for():
I = iter(xrange(1000))
return lambda: Symbol('a%i' % next(I))
def identifiers(term, s=None):
if s is None:
s = defaultdict(_names_for())
if isinstance(term, int):
return s[term]
return tuple(identifiers(inner, s) for inner in term)In [27]:
def doc_from_stack_effect(inputs, outputs):
return '(%s--%s)' % (
' '.join(map(_to_str, inputs + ('',))),
' '.join(map(_to_str, ('',) + outputs))
)
def _to_str(term):
if not isinstance(term, tuple):
try:
t = term.prefix == 's'
except AttributeError:
return str(term)
return '[.%i.]' % term.number if t else str(term)
a = []
while term and isinstance(term, tuple):
item, term = term
a.append(_to_str(item))
try:
n = term.number
except AttributeError:
n = term
else:
if term.prefix != 's':
raise ValueError('Stack label: %s' % (term,))
a.append('.%s.' % (n,))
return '[%s]' % ' '.join(a)In [28]:
def compile_(name, f, doc=None):
if doc is None:
doc = doc_from_stack_effect(*f)
inputs, outputs = identifiers(f)
i = o = Symbol('stack')
for term in inputs:
i = term, i
for term in outputs:
o = term, o
return '''def %s(stack):
"""%s"""
%s = stack
return %s''' % (name, doc, i, o)In [29]:
source = compile_('F', F)
print sourcedef F(stack):
"""([3 4 .5.] 1 2 0 -- [2 1 .5.])"""
(a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack
return ((a4, (a3, a2)), stack)
In [30]:
def F_python(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
return ((d, (c, S0)), stack)In [31]:
L = {}
eval(compile(source, '__main__', 'single'), {}, L)
L['F']Out [31]:
<function F>
In [32]:
from notebook_preamble import D, J, V
from joy.library import SimpleFunctionWrapperIn [33]:
D['F'] = SimpleFunctionWrapper(L['F'])In [34]:
J('[4 5 ...] 2 3 1 F')[3 2 ...]
In [35]:
def defs():
rolldown = (1, 2, 3), (2, 3, 1)
rollup = (1, 2, 3), (3, 1, 2)
pop = (1,), ()
swap = (1, 2), (2, 1)
rest = ((1, 2),), (2,)
rrest = C(rest, rest)
cons = (1, 2), ((1, 2),)
uncons = ((1, 2),), (1, 2)
swons = C(swap, cons)
return locals()In [36]:
for name, stack_effect_comment in sorted(defs().items()):
print
print compile_(name, stack_effect_comment)
printdef cons(stack):
"""(1 2 -- [1 .2.])"""
(a1, (a0, stack)) = stack
return ((a0, a1), stack)
def pop(stack):
"""(1 --)"""
(a0, stack) = stack
return stack
def rest(stack):
"""([1 .2.] -- 2)"""
((a0, a1), stack) = stack
return (a1, stack)
def rolldown(stack):
"""(1 2 3 -- 2 3 1)"""
(a2, (a1, (a0, stack))) = stack
return (a0, (a2, (a1, stack)))
def rollup(stack):
"""(1 2 3 -- 3 1 2)"""
(a2, (a1, (a0, stack))) = stack
return (a1, (a0, (a2, stack)))
def rrest(stack):
"""([0 1 .2.] -- 2)"""
((a0, (a1, a2)), stack) = stack
return (a2, stack)
def swap(stack):
"""(1 2 -- 2 1)"""
(a1, (a0, stack)) = stack
return (a0, (a1, stack))
def swons(stack):
"""(0 1 -- [1 .0.])"""
(a1, (a0, stack)) = stack
return ((a1, a0), stack)
def uncons(stack):
"""([1 .2.] -- 1 2)"""
((a0, a1), stack) = stack
return (a1, (a0, stack))
In [37]:
class AnyJoyType(object):
prefix = 'a'
def __init__(self, number):
self.number = number
def __repr__(self):
return self.prefix + str(self.number)
def __eq__(self, other):
return (
isinstance(other, self.__class__)
and other.prefix == self.prefix
and other.number == self.number
)
def __ge__(self, other):
return issubclass(other.__class__, self.__class__)
def __add__(self, other):
return self.__class__(self.number + other)
__radd__ = __add__
def __hash__(self):
return hash(repr(self))
class NumberJoyType(AnyJoyType): prefix = 'n'
class FloatJoyType(NumberJoyType): prefix = 'f'
class IntJoyType(FloatJoyType): prefix = 'i'
class StackJoyType(AnyJoyType):
prefix = 's'
_R = range(10)
A = map(AnyJoyType, _R)
N = map(NumberJoyType, _R)
S = map(StackJoyType, _R)In [38]:
from itertools import permutationsIn [39]:
for a, b in permutations((A[0], N[0], S[0]), 2):
print a, '>=', b, '->', a >= ba0 >= n0 -> True a0 >= s0 -> True n0 >= a0 -> False n0 >= s0 -> False s0 >= a0 -> False s0 >= n0 -> False
In [40]:
for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
print a, '>=', b, '->', a >= ba0 >= n0 -> True a0 >= f0 -> True a0 >= i0 -> True n0 >= a0 -> False n0 >= f0 -> True n0 >= i0 -> True f0 >= a0 -> False f0 >= n0 -> False f0 >= i0 -> True i0 >= a0 -> False i0 >= n0 -> False i0 >= f0 -> False
In [41]:
dup = (A[1],), (A[1], A[1])
mul = (N[1], N[2]), (N[3],)In [42]:
dupOut [42]:
((a1,), (a1, a1))
Warning:
Output truncated. This notebook contains too many cells to display efficiently.