Type checking, initial work.

This commit is contained in:
Simon Forman 2018-06-26 15:23:51 -07:00
parent 705c95ee28
commit eb739024eb
9 changed files with 1885 additions and 571 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -127,7 +127,7 @@ The simplest way to "compile" this function would be something like:
```python
def poswrd(s, e, d):
return roll_down(*swap(*pop(s, e, d)))
return rolldown(*swap(*pop(s, e, d)))
```
However, internally this function would still be allocating tuples (stack cells) and doing other unnecesssary work.
@ -829,9 +829,9 @@ We can use `compile_()` to generate many primitives in the library from their st
```python
def defs():
roll_down = (1, 2, 3), (2, 3, 1)
rolldown = (1, 2, 3), (2, 3, 1)
roll_up = (1, 2, 3), (3, 1, 2)
rollup = (1, 2, 3), (3, 1, 2)
pop = (1,), ()
@ -877,13 +877,13 @@ for name, stack_effect_comment in sorted(defs().items()):
return (a1, stack)
def roll_down(stack):
def rolldown(stack):
"""(1 2 3 -- 2 3 1)"""
(a2, (a1, (a0, stack))) = stack
return (a0, (a2, (a1, stack)))
def roll_up(stack):
def rollup(stack):
"""(1 2 3 -- 3 1 2)"""
(a2, (a1, (a0, stack))) = stack
return (a1, (a0, (a2, stack)))
@ -1218,9 +1218,9 @@ Rewrite the stack effect comments:
```python
def defs():
roll_down = (A[1], A[2], A[3]), (A[2], A[3], A[1])
rolldown = (A[1], A[2], A[3]), (A[2], A[3], A[1])
roll_up = (A[1], A[2], A[3]), (A[3], A[1], A[2])
rollup = (A[1], A[2], A[3]), (A[3], A[1], A[2])
pop = (A[1],), ()
@ -1295,8 +1295,8 @@ for name, stack_effect_comment in sorted(DEFS.items()):
popop = (a2 a1 --)
pred = (n1 -- n2)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
sqrt = (n0 -- n1)
@ -1331,7 +1331,7 @@ Revisit the `F` function, works fine.
```python
F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
F
```
@ -1361,7 +1361,7 @@ def neato(*funcs):
```python
# e.g. [swap] dip
neato(roll_up, swap, roll_down)
neato(rollup, swap, rolldown)
```
(a0 a1 a2 -- a1 a0 a2)
@ -1370,7 +1370,7 @@ neato(roll_up, swap, roll_down)
```python
# e.g. [popop] dipd
neato(popdd, roll_down, pop)
neato(popdd, rolldown, pop)
```
(a0 a1 a2 a3 -- a2 a3)
@ -1379,7 +1379,7 @@ neato(popdd, roll_down, pop)
```python
# Reverse the order of the top three items.
neato(roll_up, swap)
neato(rollup, swap)
```
(a0 a1 a2 -- a2 a1 a0)
@ -1461,8 +1461,8 @@ for name, stack_effect_comment in sorted(defs().items()):
popdd = (a3 a2 a1 -- a2 a1)
popop = (a2 a1 --)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
swap = (a1 a2 -- a2 a1)
@ -1554,16 +1554,12 @@ NEW_DEFS = {
name: (sequence_to_stack(i), sequence_to_stack(o))
for name, (i, o) in DEFS.iteritems()
}
NEW_DEFS['stack'] = S[0], (S[0], S[0])
NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1])
globals().update(NEW_DEFS)
```
```python
stack = S[0], (S[0], S[0])
```
```python
C(stack, uncons)
```
@ -1662,12 +1658,14 @@ for name, stack_effect_comment in sorted(NEW_DEFS.items()):
popop = (a2 a1 --)
pred = (n1 -- n2)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
sqrt = (n0 -- n1)
stack = (... -- ... [...])
succ = (n1 -- n2)
swaack = ([.1.] -- [.0.])
swap = (a1 a2 -- a2 a1)
swons = ([.0.] a0 -- [a0 .0.])
third = ([a0 a1 a2 .0.] -- a2)
@ -2268,14 +2266,167 @@ Obviously it would be:
Without any information about the contents of the quote we can't say much about the result.
I think there's a way forward. If we convert our list of terms we are composing into a stack structure we can use it as a *Joy expression*, then we can treat the *output half* of a function's stack effect comment as a Joy interpreter stack, and just execute combinators directly. We can hybridize the compostition function with an interpreter to evaluate combinators, compose non-combinator functions, and put type variables on the stack. For combinators like `branch` that can have more than one stack effect we have to "split universes" again and return both. (Note: bug! If one branch doesn't type check the currect code ignores it, so you can think things are okay but have a type error waiting in the faled branch, I think... D'oh! FIXME!!!)
I think there's a way forward. If we convert our list of terms we are composing into a stack structure we can use it as a *Joy expression*, then we can treat the *output half* of a function's stack effect comment as a Joy interpreter stack, and just execute combinators directly. We can hybridize the compostition function with an interpreter to evaluate combinators, compose non-combinator functions, and put type variables on the stack. For combinators like `branch` that can have more than one stack effect we have to "split universes" again and return both.
```python
stack_concat = lambda q, e: (q[0], stack_concat(q[1], e)) if q else e
class FunctionJoyType(AnyJoyType):
def __init__(self, name, sec, number):
self.name = name
self.stack_effects = sec
self.number = number
def __add__(self, other):
return self
__radd__ = __add__
def __repr__(self):
return self.name
class SymbolJoyType(FunctionJoyType): prefix = 'F'
class CombinatorJoyType(FunctionJoyType): prefix = 'C'
```
```python
def flatten(g):
return list(chain.from_iterable(g))
ID = S[0], S[0] # Identity function.
def infer(e, F=ID):
if not e:
return [F]
n, e = e
if isinstance(n, SymbolJoyType):
res = flatten(infer(e, Fn) for Fn in MC([F], n.stack_effects))
elif isinstance(n, CombinatorJoyType):
res = []
for combinator in n.stack_effects:
fi, fo = F
new_fo, ee, _ = combinator(fo, e, {})
ee = update(FUNCTIONS, ee) # Fix Symbols.
new_F = fi, new_fo
res.extend(infer(ee, new_F))
else:
lit = s9, (n, s9)
res = flatten(infer(e, Fn) for Fn in MC([F], [lit]))
return res
```
```python
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9 = F = map(FloatJoyType, _R)
i0, i1, i2, i3, i4, i5, i6, i7, i8, i9 = I = map(IntJoyType, _R)
n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 = N
s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 = S
```
```python
import joy.library
FNs = '''ccons cons divmod_ dup dupd first
over pm pop popd popdd popop pred
rest rolldown rollup rrest second
sqrt stack succ swaack swap swons
third tuck uncons'''
FUNCTIONS = {
name: SymbolJoyType(name, [NEW_DEFS[name]], i)
for i, name in enumerate(FNs.strip().split())
}
FUNCTIONS['sum'] = SymbolJoyType('sum', [(((Ns[1], s1), s0), (n0, s0))], 100)
FUNCTIONS['mul'] = SymbolJoyType('mul', [
((i2, (i1, s0)), (i3, s0)),
((f2, (i1, s0)), (f3, s0)),
((i2, (f1, s0)), (f3, s0)),
((f2, (f1, s0)), (f3, s0)),
], 101)
FUNCTIONS.update({
combo.__name__: CombinatorJoyType(combo.__name__, [combo], i)
for i, combo in enumerate((
joy.library.i,
joy.library.dip,
joy.library.dipd,
joy.library.dipdd,
joy.library.dupdip,
joy.library.b,
joy.library.x,
joy.library.infra,
))
})
def branch_true(stack, expression, dictionary):
(then, (else_, (flag, stack))) = stack
return stack, CONCAT(then, expression), dictionary
def branch_false(stack, expression, dictionary):
(then, (else_, (flag, stack))) = stack
return stack, CONCAT(else_, expression), dictionary
FUNCTIONS['branch'] = CombinatorJoyType('branch', [branch_true, branch_false], 100)
```
```python
globals().update(FUNCTIONS)
```
```python
from itertools import chain
from joy.utils.stack import list_to_stack as l2s
```
```python
expression = l2s([n1, n2, (mul, s2), (stack, s3), dip, infra, first])
```
```python
expression
```
(n1, (n2, ((mul, s2), ((stack, s3), (dip, (infra, (first, ())))))))
```python
expression = l2s([n1, n2, mul])
```
```python
infer(expression)
```
[]
```python
class SymbolJoyType(AnyJoyType):
prefix = 'F'
@ -2345,7 +2496,7 @@ For this to work the type label classes have to be modified to let `T >= t` succ
```python
F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
print doc_from_stack_effect(*F)
```
@ -2353,22 +2504,22 @@ print doc_from_stack_effect(*F)
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
TypeError Traceback (most recent call last)
<ipython-input-112-4b4cb6ff86e5> in <module>()
1 F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
<ipython-input-119-7fde90b4e88f> in <module>()
1 F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
2
----> 3 print doc_from_stack_effect(*F)
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2376,14 +2527,14 @@ print doc_from_stack_effect(*F)
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2391,14 +2542,14 @@ print doc_from_stack_effect(*F)
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2406,14 +2557,14 @@ print doc_from_stack_effect(*F)
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2421,14 +2572,14 @@ print doc_from_stack_effect(*F)
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2436,7 +2587,22 @@ print doc_from_stack_effect(*F)
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
ValueError: need more than 1 value to unpack
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
4 if not s:
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
TypeError: 'SymbolJoyType' object is not iterable

View File

@ -211,7 +211,7 @@ The simplest way to "compile" this function would be something like:
.. code:: ipython2
def poswrd(s, e, d):
return roll_down(*swap(*pop(s, e, d)))
return rolldown(*swap(*pop(s, e, d)))
However, internally this function would still be allocating tuples
(stack cells) and doing other unnecesssary work.
@ -1045,9 +1045,9 @@ from their stack effect comments:
def defs():
roll_down = (1, 2, 3), (2, 3, 1)
rolldown = (1, 2, 3), (2, 3, 1)
roll_up = (1, 2, 3), (3, 1, 2)
rollup = (1, 2, 3), (3, 1, 2)
pop = (1,), ()
@ -1094,13 +1094,13 @@ from their stack effect comments:
return (a1, stack)
def roll_down(stack):
def rolldown(stack):
"""(1 2 3 -- 2 3 1)"""
(a2, (a1, (a0, stack))) = stack
return (a0, (a2, (a1, stack)))
def roll_up(stack):
def rollup(stack):
"""(1 2 3 -- 3 1 2)"""
(a2, (a1, (a0, stack))) = stack
return (a1, (a0, (a2, stack)))
@ -1482,9 +1482,9 @@ Rewrite the stack effect comments:
def defs():
roll_down = (A[1], A[2], A[3]), (A[2], A[3], A[1])
rolldown = (A[1], A[2], A[3]), (A[2], A[3], A[1])
roll_up = (A[1], A[2], A[3]), (A[3], A[1], A[2])
rollup = (A[1], A[2], A[3]), (A[3], A[1], A[2])
pop = (A[1],), ()
@ -1559,8 +1559,8 @@ Rewrite the stack effect comments:
popop = (a2 a1 --)
pred = (n1 -- n2)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
sqrt = (n0 -- n1)
@ -1596,7 +1596,7 @@ Revisit the ``F`` function, works fine.
.. code:: ipython2
F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
F
@ -1629,7 +1629,7 @@ also get the effect of combinators in some limited cases.
.. code:: ipython2
# e.g. [swap] dip
neato(roll_up, swap, roll_down)
neato(rollup, swap, rolldown)
.. parsed-literal::
@ -1640,7 +1640,7 @@ also get the effect of combinators in some limited cases.
.. code:: ipython2
# e.g. [popop] dipd
neato(popdd, roll_down, pop)
neato(popdd, rolldown, pop)
.. parsed-literal::
@ -1651,7 +1651,7 @@ also get the effect of combinators in some limited cases.
.. code:: ipython2
# Reverse the order of the top three items.
neato(roll_up, swap)
neato(rollup, swap)
.. parsed-literal::
@ -1753,8 +1753,8 @@ comments. We can write a function to check that:
popdd = (a3 a2 a1 -- a2 a1)
popop = (a2 a1 --)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
swap = (a1 a2 -- a2 a1)
@ -1873,13 +1873,10 @@ conversion function instead. This is programmer's laziness.
name: (sequence_to_stack(i), sequence_to_stack(o))
for name, (i, o) in DEFS.iteritems()
}
NEW_DEFS['stack'] = S[0], (S[0], S[0])
NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1])
globals().update(NEW_DEFS)
.. code:: ipython2
stack = S[0], (S[0], S[0])
.. code:: ipython2
C(stack, uncons)
@ -1984,12 +1981,14 @@ Clunky junk, but it will suffice for now.
popop = (a2 a1 --)
pred = (n1 -- n2)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
sqrt = (n0 -- n1)
stack = (... -- ... [...])
succ = (n1 -- n2)
swaack = ([.1.] -- [.0.])
swap = (a1 a2 -- a2 a1)
swons = ([.0.] a0 -- [a0 .0.])
third = ([a0 a1 a2 .0.] -- a2)
@ -2686,14 +2685,159 @@ as a Joy interpreter stack, and just execute combinators directly. We
can hybridize the compostition function with an interpreter to evaluate
combinators, compose non-combinator functions, and put type variables on
the stack. For combinators like ``branch`` that can have more than one
stack effect we have to "split universes" again and return both. (Note:
bug! If one branch doesn't type check the currect code ignores it, so
you can think things are okay but have a type error waiting in the faled
branch, I think... D'oh! FIXME!!!)
stack effect we have to "split universes" again and return both.
.. code:: ipython2
stack_concat = lambda q, e: (q[0], stack_concat(q[1], e)) if q else e
class FunctionJoyType(AnyJoyType):
def __init__(self, name, sec, number):
self.name = name
self.stack_effects = sec
self.number = number
def __add__(self, other):
return self
__radd__ = __add__
def __repr__(self):
return self.name
class SymbolJoyType(FunctionJoyType): prefix = 'F'
class CombinatorJoyType(FunctionJoyType): prefix = 'C'
.. code:: ipython2
def flatten(g):
return list(chain.from_iterable(g))
ID = S[0], S[0] # Identity function.
def infer(e, F=ID):
if not e:
return [F]
n, e = e
if isinstance(n, SymbolJoyType):
res = flatten(infer(e, Fn) for Fn in MC([F], n.stack_effects))
elif isinstance(n, CombinatorJoyType):
res = []
for combinator in n.stack_effects:
fi, fo = F
new_fo, ee, _ = combinator(fo, e, {})
ee = update(FUNCTIONS, ee) # Fix Symbols.
new_F = fi, new_fo
res.extend(infer(ee, new_F))
else:
lit = s9, (n, s9)
res = flatten(infer(e, Fn) for Fn in MC([F], [lit]))
return res
.. code:: ipython2
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9 = F = map(FloatJoyType, _R)
i0, i1, i2, i3, i4, i5, i6, i7, i8, i9 = I = map(IntJoyType, _R)
n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 = N
s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 = S
.. code:: ipython2
import joy.library
FNs = '''ccons cons divmod_ dup dupd first
over pm pop popd popdd popop pred
rest rolldown rollup rrest second
sqrt stack succ swaack swap swons
third tuck uncons'''
FUNCTIONS = {
name: SymbolJoyType(name, [NEW_DEFS[name]], i)
for i, name in enumerate(FNs.strip().split())
}
FUNCTIONS['sum'] = SymbolJoyType('sum', [(((Ns[1], s1), s0), (n0, s0))], 100)
FUNCTIONS['mul'] = SymbolJoyType('mul', [
((i2, (i1, s0)), (i3, s0)),
((f2, (i1, s0)), (f3, s0)),
((i2, (f1, s0)), (f3, s0)),
((f2, (f1, s0)), (f3, s0)),
], 101)
FUNCTIONS.update({
combo.__name__: CombinatorJoyType(combo.__name__, [combo], i)
for i, combo in enumerate((
joy.library.i,
joy.library.dip,
joy.library.dipd,
joy.library.dipdd,
joy.library.dupdip,
joy.library.b,
joy.library.x,
joy.library.infra,
))
})
def branch_true(stack, expression, dictionary):
(then, (else_, (flag, stack))) = stack
return stack, CONCAT(then, expression), dictionary
def branch_false(stack, expression, dictionary):
(then, (else_, (flag, stack))) = stack
return stack, CONCAT(else_, expression), dictionary
FUNCTIONS['branch'] = CombinatorJoyType('branch', [branch_true, branch_false], 100)
.. code:: ipython2
globals().update(FUNCTIONS)
.. code:: ipython2
from itertools import chain
from joy.utils.stack import list_to_stack as l2s
.. code:: ipython2
expression = l2s([n1, n2, (mul, s2), (stack, s3), dip, infra, first])
.. code:: ipython2
expression
.. parsed-literal::
(n1, (n2, ((mul, s2), ((stack, s3), (dip, (infra, (first, ())))))))
.. code:: ipython2
expression = l2s([n1, n2, mul])
.. code:: ipython2
infer(expression)
.. parsed-literal::
[]
.. code:: ipython2
@ -2770,7 +2914,7 @@ For this to work the type label classes have to be modified to let
.. code:: ipython2
F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
print doc_from_stack_effect(*F)
@ -2780,22 +2924,22 @@ For this to work the type label classes have to be modified to let
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
TypeError Traceback (most recent call last)
<ipython-input-112-4b4cb6ff86e5> in <module>()
1 F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
<ipython-input-119-7fde90b4e88f> in <module>()
1 F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
2
----> 3 print doc_from_stack_effect(*F)
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2803,14 +2947,14 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2818,14 +2962,14 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2833,14 +2977,14 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2848,14 +2992,14 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2863,7 +3007,22 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
ValueError: need more than 1 value to unpack
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
4 if not s:
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
TypeError: 'SymbolJoyType' object is not iterable
.. code:: ipython2

File diff suppressed because one or more lines are too long

View File

@ -211,7 +211,7 @@ The simplest way to "compile" this function would be something like:
.. code:: ipython2
def poswrd(s, e, d):
return roll_down(*swap(*pop(s, e, d)))
return rolldown(*swap(*pop(s, e, d)))
However, internally this function would still be allocating tuples
(stack cells) and doing other unnecesssary work.
@ -1045,9 +1045,9 @@ from their stack effect comments:
def defs():
roll_down = (1, 2, 3), (2, 3, 1)
rolldown = (1, 2, 3), (2, 3, 1)
roll_up = (1, 2, 3), (3, 1, 2)
rollup = (1, 2, 3), (3, 1, 2)
pop = (1,), ()
@ -1094,13 +1094,13 @@ from their stack effect comments:
return (a1, stack)
def roll_down(stack):
def rolldown(stack):
"""(1 2 3 -- 2 3 1)"""
(a2, (a1, (a0, stack))) = stack
return (a0, (a2, (a1, stack)))
def roll_up(stack):
def rollup(stack):
"""(1 2 3 -- 3 1 2)"""
(a2, (a1, (a0, stack))) = stack
return (a1, (a0, (a2, stack)))
@ -1482,9 +1482,9 @@ Rewrite the stack effect comments:
def defs():
roll_down = (A[1], A[2], A[3]), (A[2], A[3], A[1])
rolldown = (A[1], A[2], A[3]), (A[2], A[3], A[1])
roll_up = (A[1], A[2], A[3]), (A[3], A[1], A[2])
rollup = (A[1], A[2], A[3]), (A[3], A[1], A[2])
pop = (A[1],), ()
@ -1559,8 +1559,8 @@ Rewrite the stack effect comments:
popop = (a2 a1 --)
pred = (n1 -- n2)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
sqrt = (n0 -- n1)
@ -1596,7 +1596,7 @@ Revisit the ``F`` function, works fine.
.. code:: ipython2
F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
F
@ -1629,7 +1629,7 @@ also get the effect of combinators in some limited cases.
.. code:: ipython2
# e.g. [swap] dip
neato(roll_up, swap, roll_down)
neato(rollup, swap, rolldown)
.. parsed-literal::
@ -1640,7 +1640,7 @@ also get the effect of combinators in some limited cases.
.. code:: ipython2
# e.g. [popop] dipd
neato(popdd, roll_down, pop)
neato(popdd, rolldown, pop)
.. parsed-literal::
@ -1651,7 +1651,7 @@ also get the effect of combinators in some limited cases.
.. code:: ipython2
# Reverse the order of the top three items.
neato(roll_up, swap)
neato(rollup, swap)
.. parsed-literal::
@ -1753,8 +1753,8 @@ comments. We can write a function to check that:
popdd = (a3 a2 a1 -- a2 a1)
popop = (a2 a1 --)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
swap = (a1 a2 -- a2 a1)
@ -1873,13 +1873,10 @@ conversion function instead. This is programmer's laziness.
name: (sequence_to_stack(i), sequence_to_stack(o))
for name, (i, o) in DEFS.iteritems()
}
NEW_DEFS['stack'] = S[0], (S[0], S[0])
NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1])
globals().update(NEW_DEFS)
.. code:: ipython2
stack = S[0], (S[0], S[0])
.. code:: ipython2
C(stack, uncons)
@ -1984,12 +1981,14 @@ Clunky junk, but it will suffice for now.
popop = (a2 a1 --)
pred = (n1 -- n2)
rest = ([a1 .1.] -- [.1.])
roll_down = (a1 a2 a3 -- a2 a3 a1)
roll_up = (a1 a2 a3 -- a3 a1 a2)
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
sqrt = (n0 -- n1)
stack = (... -- ... [...])
succ = (n1 -- n2)
swaack = ([.1.] -- [.0.])
swap = (a1 a2 -- a2 a1)
swons = ([.0.] a0 -- [a0 .0.])
third = ([a0 a1 a2 .0.] -- a2)
@ -2686,14 +2685,159 @@ as a Joy interpreter stack, and just execute combinators directly. We
can hybridize the compostition function with an interpreter to evaluate
combinators, compose non-combinator functions, and put type variables on
the stack. For combinators like ``branch`` that can have more than one
stack effect we have to "split universes" again and return both. (Note:
bug! If one branch doesn't type check the currect code ignores it, so
you can think things are okay but have a type error waiting in the faled
branch, I think... D'oh! FIXME!!!)
stack effect we have to "split universes" again and return both.
.. code:: ipython2
stack_concat = lambda q, e: (q[0], stack_concat(q[1], e)) if q else e
class FunctionJoyType(AnyJoyType):
def __init__(self, name, sec, number):
self.name = name
self.stack_effects = sec
self.number = number
def __add__(self, other):
return self
__radd__ = __add__
def __repr__(self):
return self.name
class SymbolJoyType(FunctionJoyType): prefix = 'F'
class CombinatorJoyType(FunctionJoyType): prefix = 'C'
.. code:: ipython2
def flatten(g):
return list(chain.from_iterable(g))
ID = S[0], S[0] # Identity function.
def infer(e, F=ID):
if not e:
return [F]
n, e = e
if isinstance(n, SymbolJoyType):
res = flatten(infer(e, Fn) for Fn in MC([F], n.stack_effects))
elif isinstance(n, CombinatorJoyType):
res = []
for combinator in n.stack_effects:
fi, fo = F
new_fo, ee, _ = combinator(fo, e, {})
ee = update(FUNCTIONS, ee) # Fix Symbols.
new_F = fi, new_fo
res.extend(infer(ee, new_F))
else:
lit = s9, (n, s9)
res = flatten(infer(e, Fn) for Fn in MC([F], [lit]))
return res
.. code:: ipython2
f0, f1, f2, f3, f4, f5, f6, f7, f8, f9 = F = map(FloatJoyType, _R)
i0, i1, i2, i3, i4, i5, i6, i7, i8, i9 = I = map(IntJoyType, _R)
n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 = N
s0, s1, s2, s3, s4, s5, s6, s7, s8, s9 = S
.. code:: ipython2
import joy.library
FNs = '''ccons cons divmod_ dup dupd first
over pm pop popd popdd popop pred
rest rolldown rollup rrest second
sqrt stack succ swaack swap swons
third tuck uncons'''
FUNCTIONS = {
name: SymbolJoyType(name, [NEW_DEFS[name]], i)
for i, name in enumerate(FNs.strip().split())
}
FUNCTIONS['sum'] = SymbolJoyType('sum', [(((Ns[1], s1), s0), (n0, s0))], 100)
FUNCTIONS['mul'] = SymbolJoyType('mul', [
((i2, (i1, s0)), (i3, s0)),
((f2, (i1, s0)), (f3, s0)),
((i2, (f1, s0)), (f3, s0)),
((f2, (f1, s0)), (f3, s0)),
], 101)
FUNCTIONS.update({
combo.__name__: CombinatorJoyType(combo.__name__, [combo], i)
for i, combo in enumerate((
joy.library.i,
joy.library.dip,
joy.library.dipd,
joy.library.dipdd,
joy.library.dupdip,
joy.library.b,
joy.library.x,
joy.library.infra,
))
})
def branch_true(stack, expression, dictionary):
(then, (else_, (flag, stack))) = stack
return stack, CONCAT(then, expression), dictionary
def branch_false(stack, expression, dictionary):
(then, (else_, (flag, stack))) = stack
return stack, CONCAT(else_, expression), dictionary
FUNCTIONS['branch'] = CombinatorJoyType('branch', [branch_true, branch_false], 100)
.. code:: ipython2
globals().update(FUNCTIONS)
.. code:: ipython2
from itertools import chain
from joy.utils.stack import list_to_stack as l2s
.. code:: ipython2
expression = l2s([n1, n2, (mul, s2), (stack, s3), dip, infra, first])
.. code:: ipython2
expression
.. parsed-literal::
(n1, (n2, ((mul, s2), ((stack, s3), (dip, (infra, (first, ())))))))
.. code:: ipython2
expression = l2s([n1, n2, mul])
.. code:: ipython2
infer(expression)
.. parsed-literal::
[]
.. code:: ipython2
@ -2770,7 +2914,7 @@ For this to work the type label classes have to be modified to let
.. code:: ipython2
F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
print doc_from_stack_effect(*F)
@ -2780,22 +2924,22 @@ For this to work the type label classes have to be modified to let
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
TypeError Traceback (most recent call last)
<ipython-input-112-4b4cb6ff86e5> in <module>()
1 F = reduce(C, (pop, swap, roll_down, rest, rest, cons, cons))
<ipython-input-119-7fde90b4e88f> in <module>()
1 F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
2
----> 3 print doc_from_stack_effect(*F)
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2803,14 +2947,14 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2818,14 +2962,14 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2833,14 +2977,14 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2848,14 +2992,14 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
<ipython-input-99-ddee30dbb1a6> in C(f, g)
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-98-5eb7ac5ad2c2> in compose(f, g)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
@ -2863,7 +3007,22 @@ For this to work the type label classes have to be modified to let
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
ValueError: need more than 1 value to unpack
<ipython-input-98-ddee30dbb1a6> in C(f, g)
10 def C(f, g):
11 f, g = relabel(f, g)
---> 12 for fg in compose(f, g):
13 yield delabel(fg)
<ipython-input-97-5eb7ac5ad2c2> in compose(f, g)
1 def compose(f, g):
----> 2 (f_in, f_out), (g_in, g_out) = f, g
3 s = unify(g_in, f_out)
4 if not s:
5 raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
TypeError: 'SymbolJoyType' object is not iterable
.. code:: ipython2

View File

@ -2,7 +2,7 @@
Multiple Stack Effects
By adjusting the machinery in types.py to handles lists of stackeffect comments
By adjusting the machinery in types.py to handles lists of stack effect comments
we can capture more information about the type signatures of some functions,
and we can introduce a kind of Kleene Star or sequence type that can stand for
an unbounded sequence of other types.
@ -13,6 +13,7 @@ from itertools import chain, product
import sys
sys.path.append('/home/sforman/Desktop/Joypy-hg')
import joy.library
from joy.parser import Symbol
from joy.utils.stack import concat as CONCAT
from joy.utils.types import (
AnyJoyType, A,
@ -125,12 +126,11 @@ def unify(u, v, s=None):
return _lil_uni(u, v, s)
if isinstance(u, tuple) and isinstance(v, tuple):
if len(u) != len(v) != 2:
raise JoyTypeError(repr((u, v)))
if len(u) != 2 or len(v) != 2:
raise JoyTypeError('Cannot unify %r and %r.' % (u, v))
a, b = v
(a, b), (c, d) = v, u
if isinstance(a, KleeneStar):
c, d = u
if isinstance(c, KleeneStar):
s = _lil_uni(a, c, s) # Attempt to unify the two K-stars.
return unify(d, b, s[0])
@ -147,20 +147,13 @@ def unify(u, v, s=None):
sn.update(s)
return t
a, b = u
if isinstance(a, KleeneStar):
s0 = unify(v, b)
s1 = unify(v, (a.another(), u))
t = s0 + s1
if isinstance(c, KleeneStar):
t = unify(v, d) + unify(v, (c.another(), u))
for sn in t:
sn.update(s)
sn.update(s)
return t
ses = unify(u[0], v[0], s)
results = ()
for sn in ses:
results += unify(u[1], v[1], sn)
return results
return tuple(flatten(unify(d, b, sn) for sn in unify(c, a, s)))
if isinstance(v, tuple):
if not stacky(u):
@ -174,7 +167,7 @@ def unify(u, v, s=None):
s[v] = u
return s,
return ()
return _lil_uni(u, v, s)
def _lil_uni(u, v, s):
@ -214,7 +207,8 @@ def MC(F, G):
return res
flatten = lambda g: list(chain.from_iterable(g))
def flatten(g):
return list(chain.from_iterable(g))
ID = S[0], S[0] # Identity function.
@ -256,25 +250,23 @@ Ns = map(NumberStarJoyType, _R)
Ss = map(StackStarJoyType, _R)
mul = [
((i2, (i1, s0)), (i3, s0)),
((f2, (i1, s0)), (f3, s0)),
((i2, (f1, s0)), (f3, s0)),
((f2, (f1, s0)), (f3, s0)),
]
FUNCTIONS = {
name: SymbolJoyType(name, [DEFS[name]], i)
for i, name in enumerate('''
ccons cons divmod_ dup dupd first
mul over pm pop popd popdd popop
pred rest rolldown rollup rrest
second sqrt succ swap swons third
tuck uncons stack swaack
over pm pop popd popdd popop pred
rest rolldown rollup rrest second
sqrt stack succ swaack swap swons
third tuck uncons
'''.strip().split())
}
FUNCTIONS['sum'] = SymbolJoyType('sum', [(((Ns[1], s1), s0), (n0, s0))], 100)
FUNCTIONS['mul'] = SymbolJoyType('mul', [
((i2, (i1, s0)), (i3, s0)),
((f2, (i1, s0)), (f3, s0)),
((i2, (f1, s0)), (f3, s0)),
((f2, (f1, s0)), (f3, s0)),
], 101)
FUNCTIONS.update({
combo.__name__: CombinatorJoyType(combo.__name__, [combo], i)
for i, combo in enumerate((
@ -300,6 +292,52 @@ def branch_false(stack, expression, dictionary):
FUNCTIONS['branch'] = CombinatorJoyType('branch', [branch_true, branch_false], 100)
globals().update(FUNCTIONS)
def _ge(self, other):
return (issubclass(other.__class__, self.__class__)
or hasattr(self, 'accept')
and isinstance(other, self.accept))
AnyJoyType.__ge__ = _ge
AnyJoyType.accept = tuple, int, float, long, str, unicode, bool, Symbol
StackJoyType.accept = tuple
if __name__ == '__main__':
from joy.parser import text_to_expression
from joy.utils.stack import list_to_stack as l2s
F = infer(l2s((pop, pop, pop)))
for f in F:
print doc_from_stack_effect(*f)
s = text_to_expression('0 1 2')
L = unify(s, F[0][0])
print L
print
F = infer(l2s((pop, swap, rolldown, rest, rest, cons, cons)))
for f in F:
print doc_from_stack_effect(*f)
s = text_to_expression('0 1 2 [3 4]')
L = unify(s, F[0][0])
print L
print
g = update(L[0], F[0])
print doc_from_stack_effect(*g)
print g
print '- - - - - -'
s = text_to_expression('[3 4]')
L = unify(s, F[0][1])
print L
print
g = update(L[0], F[0])
print doc_from_stack_effect(*g)
print g

View File

@ -186,7 +186,7 @@ def _f(term, switch):
while term and isinstance(term, tuple):
item, term = term
a.append(item)
assert isinstance(term, StackJoyType), repr(term)
assert isinstance(term, (tuple, StackJoyType)), repr(term)
a = [_to_str(i, term, switch) for i in a]
return a
@ -206,10 +206,11 @@ def _to_str(term, stack, switch):
while term and isinstance(term, tuple):
item, term = term
a.append(_to_str(item, stack, switch))
assert isinstance(term, StackJoyType), repr(term)
assert isinstance(term, (tuple, StackJoyType)), repr(term)
if term == stack:
switch[0] = True
end = '...'
end = '' if term == () else '...'
#end = '...'
else:
end = '...%i' % term.number
a.append(end)

View File

@ -18,7 +18,7 @@ class TestMixin(object):
self.assert_(a >= b)
self.assert_(b >= a)
# Check type variables match expected pattern.
self._compare_structures(a, b)
self._compare_structures(b, a)
def _compare_structures(self, a, b, seen=None):
# Sometimes we change ONLY the "number" attr of our type vars.
@ -33,12 +33,12 @@ class TestMixin(object):
self._compare_structures(aa, bb, seen)
else:
if a in seen:
self.assertIs(b, seen[a])
self.assertEqual(b, seen[a])
seen[a] = b
class TestCombinators(TestMixin, unittest.TestCase):
# def setUp(self):
# def tearDown(self):
@ -76,9 +76,19 @@ class TestCombinators(TestMixin, unittest.TestCase):
(mul, s2),
infra
]
f = (s0, ((n0, (n1, s1)), s2))
# (-- [n0 n1 ...1]) Two numbers in a stack.
self.assertEqualTypeStructure(infr(expression), [f])
f = [
(s1, ((f1, (n1, s2)), s3)), # (-- [f1 n1 ...2])
(s1, ((i1, (n1, s2)), s3)), # (-- [i1 n1 ...2])
]
self.assertEqualTypeStructure(infr(expression), f)
def test_nullary(self):
expression = n1, n2, (mul, s2), (stack, s3), dip, infra, first
f = [
(s1, (f1, (n1, (n2, s2)))), # (-- n2 n1 f1)
(s1, (i1, (n1, (n2, s2)))), # (-- n2 n1 i1)
]
self.assertEqualTypeStructure(infr(expression), f)
def test_x(self):
expression = (a1, (swap, ((dup, s2), (dip, s0)))), x
@ -129,6 +139,17 @@ class TestYin(TestMixin, unittest.TestCase):
f = (s0, ((a0, s0), (a1, s1))) # (-- a1 [a0 ...0])
self.assertEqualTypeStructure(infr(expression), [f])
def test_z_down(self):
expression = s2, swap, uncons, swap
f = (((a1, s1), s2), (a1, (s1, (s3, s2))))
# ([a1 ...1] -- [...3] [...1] a1)
self.assertEqualTypeStructure(infr(expression), [f])
def test_z_right(self):
expression = a1, a2, (swons, s3), cons, dip, uncons, swap
f = ((s1, s2), (a1, (s3, ((a2, s1), s2))))
# ([...1] -- [a2 ...1] [...3] a1)
self.assertEqualTypeStructure(infr(expression), [f])
## def test_(self):
## expression = pop, swap, rolldown, rest, rest, cons, cons