Minor edits.

This commit is contained in:
Simon Forman
2018-06-27 16:31:00 -07:00
parent 4321ea874b
commit 9ee50a6268
9 changed files with 2137 additions and 2127 deletions
+269 -255
View File
@@ -1,15 +1,11 @@
# Type Inference
This notebook presents a simple type inferencer for Joy code. It can infer the stack effect of most Joy expressions. It built largely by means of existing ideas and research (some of it may be original but I'm not able to say, as I don't fully understand the all of the source material in the depth required to make that call.) A great overview of the existing knowledge is a talk ["Type Inference in Stack-Based Programming Languages"](http://prl.ccs.neu.edu/blog/2017/03/10/type-inference-in-stack-based-programming-languages/) given by Rob Kleffner on or about 2017-03-10 as part of a course on the history of programming languages.
This notebook presents a simple type inferencer for Joy code. It can infer the stack effect of most Joy expressions. It's built largely by means of existing ideas and research. (A great overview of the existing knowledge is a talk ["Type Inference in Stack-Based Programming Languages"](http://prl.ccs.neu.edu/blog/2017/03/10/type-inference-in-stack-based-programming-languages/) given by Rob Kleffner on or about 2017-03-10 as part of a course on the history of programming languages.)
The notebook starts with a simple inferencer based on the work of Jaanus Pöial which we then progressively elaborate to cover more Joy semantics. Along the way we write a simple "compiler" that emits Python code for what I like to call Yin functions.
The notebook starts with a simple inferencer based on the work of Jaanus Pöial which we then progressively elaborate to cover more Joy semantics. Along the way we write a simple "compiler" that emits Python code for what I like to call Yin functions. (Yin functions are those that only rearrange values in stacks, as opposed to Yang functions that actually work on the values themselves.)
Yin functions are those that only rearrange values in stacks, as opposed to Yang functions that actually work on the values themselves. It's interesting to note that a Joy with *only* stacks (no other kinds of values) can be made and is Turing-complete, therefore all Yang functions are actually Yin functions, and all computation can be performed by manipulations of structures of containers, which is a restatement of the Laws of Form. (Also, this implies that every program can be put into a form such that it can be computed in a single step, although that step may be enormous or unending.)
Although I haven't completed it yet, a Joy based on Laws of Form provides the foundation for a provably correct computing system "down to the metal". This is my original and still primary motivation for developing Joy. (I want a proven-correct Operating System for a swarm of trash-collecting recycler robots. To trust it I have to implementment it myself from first principles, and I'm not smart enough to truly grok the existing literature and software, so I had to go look for and find LoF and Joy. Now that I have the mental tools to build my robot OS I can get down to it.
Anyhow, here's type inference...
## Part I: Pöial's Rules
@@ -147,7 +143,7 @@ def poswrd(stack):
This eliminates the internal work of the first version. Because this function only rearranges the stack and doesn't do any actual processing on the stack items themselves all the information needed to implement it is in the stack effect comment.
### Functions on Lists
### Functions on Stacks
These are slightly tricky.
rest ( [1 ...] -- [...] )
@@ -345,18 +341,12 @@ def unify(u, v, s=None):
if s is None:
s = {}
if u == v:
return s
if isinstance(u, int):
s[u] = v
return s
if isinstance(v, int):
elif isinstance(v, int):
s[v] = u
return s
return False
return s
```
### `update()`
@@ -566,9 +556,6 @@ except Exception, e:
print e
```
Cannot unify (1, 2) and (1001, 1002).
#### `unify()` version 2
The problem is that the `unify()` function as written doesn't handle the case when both terms are tuples. We just have to add a clause to deal with this recursively:
@@ -581,27 +568,24 @@ def unify(u, v, s=None):
u = update(s, u)
v = update(s, v)
if u == v:
return s
if isinstance(u, int):
s[u] = v
return s
if isinstance(v, int):
elif isinstance(v, int):
s[v] = u
return s
if isinstance(u, tuple) and isinstance(v, tuple):
if len(u) != len(v) != 2:
raise ValueError(repr((u, v)))
for uu, vv in zip(u, v):
s = unify(uu, vv, s)
if s == False: # (instead of a substitution dict.)
break
return s
return False
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)
return s
```
@@ -1142,7 +1126,7 @@ def delabel(f, seen=None, c=None):
pass
if not isinstance(f, tuple):
seen[f] = f.__class__(c[f.prefix])
seen[f] = f.__class__(c[f.prefix] + 1)
c[f.prefix] += 1
return seen[f]
@@ -1157,7 +1141,7 @@ delabel(foo)
(((a0,), (a0, a0)), ((n0, n1), (n2,)))
(((a1,), (a1, a1)), ((n1, n2), (n3,)))
@@ -1280,7 +1264,7 @@ for name, stack_effect_comment in sorted(DEFS.items()):
print name, '=', doc_from_stack_effect(*stack_effect_comment)
```
ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
ccons = (a1 a2 [.1.] -- [a1 a2 .1.])
cons = (a1 [.1.] -- [a1 .1.])
divmod_ = (n2 n1 -- n4 n3)
dup = (a1 -- a1 a1)
@@ -1297,13 +1281,13 @@ for name, stack_effect_comment in sorted(DEFS.items()):
rest = ([a1 .1.] -- [.1.])
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)
rrest = ([a1 a2 .1.] -- [.1.])
second = ([a1 a2 .1.] -- a2)
sqrt = (n1 -- n2)
succ = (n1 -- n2)
swap = (a1 a2 -- a2 a1)
swons = ([.0.] a0 -- [a0 .0.])
third = ([a0 a1 a2 .0.] -- a2)
swons = ([.1.] a1 -- [a1 .1.])
third = ([a1 a2 a3 .1.] -- a3)
tuck = (a2 a1 -- a1 a2 a1)
uncons = ([a1 .1.] -- a1 [.1.])
@@ -1323,7 +1307,7 @@ C(dup, mul)
((n0,), (n1,))
((n1,), (n2,))
@@ -1338,7 +1322,7 @@ F
(((a0, (a1, s0)), a2, a3, a4), ((a3, (a2, s0)),))
(((a1, (a2, s1)), a3, a4, a5), ((a4, (a3, s1)),))
@@ -1347,7 +1331,7 @@ F
print doc_from_stack_effect(*F)
```
([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])
([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.])
Some otherwise inefficient functions are no longer to be feared. We can also get the effect of combinators in some limited cases.
@@ -1364,7 +1348,7 @@ def neato(*funcs):
neato(rollup, swap, rolldown)
```
(a0 a1 a2 -- a1 a0 a2)
(a1 a2 a3 -- a2 a1 a3)
@@ -1373,7 +1357,7 @@ neato(rollup, swap, rolldown)
neato(popdd, rolldown, pop)
```
(a0 a1 a2 a3 -- a2 a3)
(a1 a2 a3 a4 -- a3 a4)
@@ -1382,7 +1366,7 @@ neato(popdd, rolldown, pop)
neato(rollup, swap)
```
(a0 a1 a2 -- a2 a1 a0)
(a1 a2 a3 -- a3 a2 a1)
#### `compile_()` version 2
@@ -1411,9 +1395,9 @@ print compile_('F', F)
```
def F(stack):
"""([a0 a1 .0.] a2 a3 a4 -- [a3 a2 .0.])"""
(a4, (a3, (a2, ((a0, (a1, s0)), stack)))) = stack
return ((a3, (a2, s0)), stack)
"""([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.])"""
(a5, (a4, (a3, ((a1, (a2, s1)), stack)))) = stack
return ((a4, (a3, s1)), stack)
But it cannot magically create new functions that involve e.g. math and such. Note that this is *not* a `sqr` function implementation:
@@ -1424,9 +1408,9 @@ print compile_('sqr', C(dup, mul))
```
def sqr(stack):
"""(n0 -- n1)"""
(n0, stack) = stack
return (n1, stack)
"""(n1 -- n2)"""
(n1, stack) = stack
return (n2, stack)
(Eventually I should come back around to this becuase it's not tooo difficult to exend this code to be able to compile e.g. `n3 = mul(n1, n2)` for `mul` and insert it in the right place with the right variable names. It requires a little more support from the library functions, in that we need to know to call `mul()` the Python function for `mul` the Joy function, but since *most* of the math functions (at least) are already wrappers it should be straightforward.)
@@ -1450,7 +1434,7 @@ for name, stack_effect_comment in sorted(defs().items()):
print name, '=', doc_from_stack_effect(*stack_effect_comment)
```
ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
ccons = (a1 a2 [.1.] -- [a1 a2 .1.])
cons = (a1 [.1.] -- [a1 .1.])
dup = (a1 -- a1 a1)
dupd = (a2 a1 -- a2 a2 a1)
@@ -1463,11 +1447,11 @@ for name, stack_effect_comment in sorted(defs().items()):
rest = ([a1 .1.] -- [.1.])
rolldown = (a1 a2 a3 -- a2 a3 a1)
rollup = (a1 a2 a3 -- a3 a1 a2)
rrest = ([a0 a1 .0.] -- [.0.])
second = ([a0 a1 .0.] -- a1)
rrest = ([a1 a2 .1.] -- [.1.])
second = ([a1 a2 .1.] -- a2)
swap = (a1 a2 -- a2 a1)
swons = ([.0.] a0 -- [a0 .0.])
third = ([a0 a1 a2 .0.] -- a2)
swons = ([.1.] a1 -- [a1 .1.])
third = ([a1 a2 a3 .1.] -- a3)
tuck = (a2 a1 -- a1 a2 a1)
uncons = ([a1 .1.] -- a1 [.1.])
@@ -1530,7 +1514,7 @@ Let's try `stack∘uncons∘uncons`:
It works.
#### `compose()` version 2
This function has to be modified to use the new datastructures and it is no longer recursive, instead recursion happens as part of unification. Further, the first and second of Pöial's rules are now handled automatically by the unification algorithm.
This function has to be modified to use the new datastructures and it is no longer recursive, instead recursion happens as part of unification. Further, the first and second of Pöial's rules are now handled automatically by the unification algorithm. (One easy way to see this is that now an empty stack effect comment is represented by a `StackJoyType` instance which is not "falsey" and so neither of the first two rules' `if` clauses will ever be `True`. Later on I change the "truthiness" of `StackJoyType` to false to let e.g. `joy.utils.stack.concat` work with our stack effect comment cons-list tuples.)
```python
@@ -1567,19 +1551,19 @@ C(stack, uncons)
((a0, s0), (s0, (a0, (a0, s0))))
((a1, s1), (s1, (a1, (a1, s1))))
```python
C(C(stack, uncons), uncons)
reduce(C, (stack, uncons, uncons))
```
((a0, (a1, s0)), (s0, (a1, (a0, (a0, (a1, s0))))))
((a1, (a2, s1)), (s1, (a2, (a1, (a1, (a2, s1))))))
@@ -1643,7 +1627,7 @@ for name, stack_effect_comment in sorted(NEW_DEFS.items()):
print name, '=', doc_from_stack_effect(*stack_effect_comment)
```
ccons = (a0 a1 [.0.] -- [a0 a1 .0.])
ccons = (a1 a2 [.1.] -- [a1 a2 .1.])
cons = (a1 [.1.] -- [a1 .1.])
divmod_ = (n2 n1 -- n4 n3)
dup = (a1 -- a1 a1)
@@ -1660,15 +1644,15 @@ for name, stack_effect_comment in sorted(NEW_DEFS.items()):
rest = ([a1 .1.] -- [.1.])
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)
rrest = ([a1 a2 .1.] -- [.1.])
second = ([a1 a2 .1.] -- a2)
sqrt = (n1 -- n2)
stack = (... -- ... [...])
succ = (n1 -- n2)
swaack = ([.1.] -- [.0.])
swap = (a1 a2 -- a2 a1)
swons = ([.0.] a0 -- [a0 .0.])
third = ([a0 a1 a2 .0.] -- a2)
swons = ([.1.] a1 -- [a1 .1.])
third = ([a1 a2 a3 .1.] -- a3)
tuck = (a2 a1 -- a1 a2 a1)
uncons = ([a1 .1.] -- a1 [.1.])
@@ -1677,18 +1661,18 @@ for name, stack_effect_comment in sorted(NEW_DEFS.items()):
```python
print ; print doc_from_stack_effect(*stack)
print ; print doc_from_stack_effect(*C(stack, uncons))
print ; print doc_from_stack_effect(*C(C(stack, uncons), uncons))
print ; print doc_from_stack_effect(*C(C(stack, uncons), cons))
print ; print doc_from_stack_effect(*reduce(C, (stack, uncons, uncons)))
print ; print doc_from_stack_effect(*reduce(C, (stack, uncons, cons)))
```
(... -- ... [...])
(... a0 -- ... a0 a0 [...])
(... a1 -- ... a1 a1 [...])
(... a1 a0 -- ... a1 a0 a0 a1 [...])
(... a2 a1 -- ... a2 a1 a1 a2 [...])
(... a0 -- ... a0 [a0 ...])
(... a1 -- ... a1 [a1 ...])
@@ -1696,7 +1680,7 @@ print ; print doc_from_stack_effect(*C(C(stack, uncons), cons))
print doc_from_stack_effect(*C(ccons, stack))
```
(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])
(... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])
@@ -1709,7 +1693,7 @@ Q
((s0, (a0, (a1, s1))), (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1)))
((s1, (a1, (a2, s2))), (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2)))
@@ -1734,9 +1718,9 @@ print compile_('Q', Q)
```
def Q(stack):
"""(... a1 a0 [.0.] -- ... [a1 a0 .0.] [[a1 a0 .0.] ...])"""
(s0, (a0, (a1, s1))) = stack
return (((a1, (a0, s0)), s1), ((a1, (a0, s0)), s1))
"""(... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])"""
(s1, (a1, (a2, s2))) = stack
return (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2))
@@ -1766,7 +1750,7 @@ print doc_from_stack_effect(*enstacken)
print doc_from_stack_effect(*C(cons, unstack))
```
(a0 [.0.] -- a0)
(a1 [.1.] -- a1)
@@ -1774,7 +1758,7 @@ print doc_from_stack_effect(*C(cons, unstack))
print doc_from_stack_effect(*C(cons, enstacken))
```
(a0 [.0.] -- [[a0 .0.] .1.])
(a1 [.1.] -- [[a1 .1.] .2.])
@@ -1785,7 +1769,7 @@ C(cons, unstack)
((s0, (a0, s1)), (a0, s0))
((s1, (a1, s2)), (a1, s1))
@@ -1833,8 +1817,8 @@ for f in muls:
print doc_from_stack_effect(*dup), doc_from_stack_effect(*f), doc_from_stack_effect(*e)
```
(a1 -- a1 a1) (i1 i2 -- i3) (i0 -- i1)
(a1 -- a1 a1) (f1 f2 -- f3) (f0 -- f1)
(a1 -- a1 a1) (i1 i2 -- i3) (i1 -- i2)
(a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2)
@@ -1855,22 +1839,22 @@ def MC(F, G):
```
```python
for f in MC([dup], muls):
print doc_from_stack_effect(*f)
```
(f0 -- f1)
(i0 -- i1)
```python
for f in MC([dup], [mul]):
print doc_from_stack_effect(*f)
```
(n0 -- n1)
(n1 -- n2)
```python
for f in MC([dup], muls):
print doc_from_stack_effect(*f)
```
(f1 -- f2)
(i1 -- i2)
### Representing an Unbounded Sequence of Types
@@ -2155,8 +2139,8 @@ for f in MC([dup], muls):
print doc_from_stack_effect(*f)
```
(f0 -- f1)
(i0 -- i1)
(f1 -- f2)
(i1 -- i2)
@@ -2167,7 +2151,7 @@ for f in MC([dup], [sum_]):
print doc_from_stack_effect(*f)
```
([n0* .0.] -- [n0* .0.] n0)
([n1* .1.] -- [n1* .1.] n1)
@@ -2178,8 +2162,8 @@ for f in MC([cons], [sum_]):
print doc_from_stack_effect(*f)
```
(a0 [.0.] -- n0)
(n0 [n0* .0.] -- n1)
(a1 [.1.] -- n1)
(n1 [n1* .1.] -- n2)
@@ -2192,7 +2176,7 @@ for f in MC([cons], [sum_]):
print doc_from_stack_effect(*f)
```
(a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n0 [n0* .0.] -- n1)
(a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n1 [n1* .1.] -- n2)
@@ -2415,6 +2399,18 @@ expression = l2s([n1, n2, mul])
```
```python
expression
```
(n1, (n2, (mul, ())))
```python
infer(expression)
```
@@ -2422,72 +2418,78 @@ infer(expression)
[]
[(s1, (f1, s1)), (s1, (i1, s1))]
```python
class SymbolJoyType(AnyJoyType):
prefix = 'F'
def __init__(self, name, sec, number):
self.name = name
self.stack_effects = sec
self.number = number
class CombinatorJoyType(SymbolJoyType): prefix = 'C'
def dip_t(stack, expression):
(quote, (a1, stack)) = stack
expression = stack_concat(quote, (a1, expression))
return stack, expression
CONS = SymbolJoyType('cons', [cons], 23)
DIP = CombinatorJoyType('dip', [dip_t], 44)
def kav(F, e):
#i, stack = F
if not e:
return [(F, e)]
n, e = e
if isinstance(n, SymbolJoyType):
Fs = []
for sec in n.stack_effects:
Fs.extend(MC([F], sec))
return [kav(Fn, e) for Fn in Fs]
if isinstance(n, CombinatorJoyType):
res = []
for f in n.stack_effects:
s, e = f(F[1], e)
new_F = F[0], s
res.extend(kav(new_F, e))
return res
lit = S[0], (n, S[0])
return [kav(Fn, e) for Fn in MC([F], [lit])]
infer(expression)
```
compare, and be amazed:
[(s1, (f1, s1)), (s1, (i1, s1))]
```python
def dip_t(stack, expression):
(quote, (a1, stack)) = stack
expression = stack_concat(quote, (a1, expression))
return stack, expression
for stack_effect_comment in infer(expression):
print doc_from_stack_effect(*stack_effect_comment)
```
(-- f1)
(-- i1)
```python
def dip(stack, expression, dictionary):
(quote, (x, stack)) = stack
expression = (x, expression)
return stack, concat(quote, expression), dictionary
expression
```
And that brings us to current Work-In-Progress. I'm pretty hopeful that the mixed-mode inferencer/interpreter `kav()` function along with the ability to specify multiple implementations for the combinators will permit modelling of the stack effects of e.g. `ifte`. If I can keep up the pace I should be able to verify that conjecture by the end of June.
(n1, (n2, (mul, ())))
```python
infer(expression)
```
[(s1, (f1, s1)), (s1, (i1, s1))]
And that brings us to current Work-In-Progress. I'm pretty hopeful that the mixed-mode inferencer/interpreter `infer()` function along with the ability to specify multiple implementations for the combinators will permit modelling of the stack effects of e.g. `ifte`. If I can keep up the pace I should be able to verify that conjecture by the end of June.
## Conclusion
(for now...)
Work remains to be done:
- the rest of the library has to be covered
- figure out how to deal with `loop` and `genrec`, etc..
- extend the types to check values (see the appendix)
- other kinds of "higher order" type variables, OR, AND, etc..
- maybe rewrite in Prolog for great good?
- definitions
- don't permit composition of functions that don't compose
- auto-compile compilable functions
- Compiling more than just the Yin functions.
- getting better visibility (than Python debugger.)
- DOOOOCS!!!! Lots of docs!
- docstrings all around
- improve this notebook (it kinda falls apart at the end narratively. I went off and just started writing code to see if it would work. It does, but now I have to come back and describe here what I did.
I'm starting to realize that, with the inferencer/checker/compiler coming along, and with the UI ready to be rewritten in Joy, I'm close to a time when my ephasis is going to have to shift from crunchy code stuff to squishy human stuff. I'm going to have to put normal people in front of this and see if, in fact, they *can* learn the basics of programming with it.
The rest of this stuff is junk and/or unfinished material.
@@ -2496,113 +2498,25 @@ For this to work the type label classes have to be modified to let `T >= t` succ
```python
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
def _ge(self, other):
return (issubclass(other.__class__, self.__class__)
or hasattr(self, 'accept')
and isinstance(other, self.accept))
print doc_from_stack_effect(*F)
AnyJoyType.__ge__ = _ge
AnyJoyType.accept = tuple, int, float, long, str, unicode, bool, Symbol
StackJoyType.accept = tuple
```
---------------------------------------------------------------------------
```python
F = infer(l2s((pop, swap, rolldown, rest, rest, cons, cons)))
TypeError Traceback (most recent call last)
for f in F:
print doc_from_stack_effect(*f)
```
<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-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))
<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))
<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))
<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))
<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))
<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
([a4 a5 .1.] a3 a2 a1 -- [a2 a3 .1.])
@@ -2612,31 +2526,131 @@ from joy.parser import text_to_expression
```python
s = text_to_expression('[3 4 ...] 2 1')
F = infer(l2s((pop, pop, pop)))
for f in F:
print doc_from_stack_effect(*f)
```
(a3 a2 a1 --)
```python
s = text_to_expression('0 1 2')
s
```
(0, (1, (2, ())))
```python
L = unify(F[1], s)
F[0][0]
```
(a1, (a2, (a3, s1)))
```python
L = unify(s, F[0][0])
L
```
()
```python
F[1]
s = text_to_expression('0 1 2 [3 4]')
s
```
(0, (1, (2, ((3, (4, ())), ()))))
```python
F[0][0]
```
(a1, (a2, (a3, s1)))
```python
L = unify(s, F[0][0])
L
```
()
```python
L = unify(F[0][0], s)
L
```
()
```python
F[1][0]
```
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-133-58a8e44e9cba> in <module>()
----> 1 F[1][0]
IndexError: list index out of range
```python
s[0]
```
```python
A[1] >= 23
```
## [Abstract Interpretation](https://en.wikipedia.org/wiki/Abstract_interpretation)
I *think* this might be sorta what I'm doing above with the `kav()` function...
In any event "mixed-mode" interpreters that include values and type variables and can track constraints, etc. will be, uh, super-useful. And Abstract Interpretation should be a rich source of ideas.