Convert syntax highlighter spec.

This commit is contained in:
Simon Forman 2021-11-19 13:57:36 -08:00
parent 31c26cd235
commit 3f40e30c6f
12 changed files with 361 additions and 361 deletions

View File

@ -76,7 +76,7 @@ E.g.:
Implementation Implementation
-------------- --------------
.. code:: ipython2 .. code:: python
from functools import partial as curry from functools import partial as curry
from itertools import product from itertools import product
@ -86,7 +86,7 @@ Implementation
The empty set and the set of just the empty string. The empty set and the set of just the empty string.
.. code:: ipython2 .. code:: python
phi = frozenset() # ϕ phi = frozenset() # ϕ
y = frozenset({''}) # λ y = frozenset({''}) # λ
@ -101,7 +101,7 @@ alphabet with two symbols (if you had to.)
I chose the names ``O`` and ``l`` (uppercase “o” and lowercase “L”) to I chose the names ``O`` and ``l`` (uppercase “o” and lowercase “L”) to
look like ``0`` and ``1`` (zero and one) respectively. look like ``0`` and ``1`` (zero and one) respectively.
.. code:: ipython2 .. code:: python
syms = O, l = frozenset({'0'}), frozenset({'1'}) syms = O, l = frozenset({'0'}), frozenset({'1'})
@ -123,7 +123,7 @@ expression* is one of:
Where ``R`` and ``S`` stand for *regular expressions*. Where ``R`` and ``S`` stand for *regular expressions*.
.. code:: ipython2 .. code:: python
AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split() # Tags are just strings. AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split() # Tags are just strings.
@ -133,7 +133,7 @@ only, these datastructures are immutable.
String Representation of RE Datastructures String Representation of RE Datastructures
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
def stringy(re): def stringy(re):
''' '''
@ -175,11 +175,11 @@ Match anything. Often spelled “.”
I = (0|1)* I = (0|1)*
.. code:: ipython2 .. code:: python
I = (KSTAR, (OR, O, l)) I = (KSTAR, (OR, O, l))
.. code:: ipython2 .. code:: python
print stringy(I) print stringy(I)
@ -201,14 +201,14 @@ The example expression from Brzozowski:
Note that it contains one of everything. Note that it contains one of everything.
.. code:: ipython2 .. code:: python
a = (CONS, I, (CONS, l, (CONS, l, (CONS, l, I)))) a = (CONS, I, (CONS, l, (CONS, l, (CONS, l, I))))
b = (CONS, I, (CONS, O, l)) b = (CONS, I, (CONS, O, l))
c = (CONS, l, (KSTAR, l)) c = (CONS, l, (KSTAR, l))
it = (AND, a, (NOT, (OR, b, c))) it = (AND, a, (NOT, (OR, b, c)))
.. code:: ipython2 .. code:: python
print stringy(it) print stringy(it)
@ -223,7 +223,7 @@ Note that it contains one of everything.
Lets get that auxiliary predicate function ``δ`` out of the way. Lets get that auxiliary predicate function ``δ`` out of the way.
.. code:: ipython2 .. code:: python
def nully(R): def nully(R):
''' '''
@ -263,7 +263,7 @@ This is the straightforward version with no “compaction”. It works fine,
but does waaaay too much work because the expressions grow each but does waaaay too much work because the expressions grow each
derivation. derivation.
.. code:: ipython2 .. code:: python
def D(symbol): def D(symbol):
@ -308,7 +308,7 @@ derivation.
Compaction Rules Compaction Rules
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
def _compaction_rule(relation, one, zero, a, b): def _compaction_rule(relation, one, zero, a, b):
return ( return (
@ -320,7 +320,7 @@ Compaction Rules
An elegant symmetry. An elegant symmetry.
.. code:: ipython2 .. code:: python
# R ∧ I = I ∧ R = R # R ∧ I = I ∧ R = R
# R ∧ ϕ = ϕ ∧ R = ϕ # R ∧ ϕ = ϕ ∧ R = ϕ
@ -341,7 +341,7 @@ We can save re-processing by remembering results we have already
computed. RE datastructures are immutable and the ``derv()`` functions computed. RE datastructures are immutable and the ``derv()`` functions
are *pure* so this is fine. are *pure* so this is fine.
.. code:: ipython2 .. code:: python
class Memo(object): class Memo(object):
@ -365,7 +365,7 @@ With “Compaction”
This version uses the rules above to perform compaction. It keeps the This version uses the rules above to perform compaction. It keeps the
expressions from growing too large. expressions from growing too large.
.. code:: ipython2 .. code:: python
def D_compaction(symbol): def D_compaction(symbol):
@ -414,7 +414,7 @@ Lets try it out…
(FIXME: redo.) (FIXME: redo.)
.. code:: ipython2 .. code:: python
o, z = D_compaction('0'), D_compaction('1') o, z = D_compaction('0'), D_compaction('1')
REs = set() REs = set()
@ -605,20 +605,20 @@ You can see the one-way nature of the ``g`` state and the ``hij`` “trap”
in the way that the ``.111.`` on the left-hand side of the ``&`` in the way that the ``.111.`` on the left-hand side of the ``&``
disappears once it has been matched. disappears once it has been matched.
.. code:: ipython2 .. code:: python
from collections import defaultdict from collections import defaultdict
from pprint import pprint from pprint import pprint
from string import ascii_lowercase from string import ascii_lowercase
.. code:: ipython2 .. code:: python
d0, d1 = D_compaction('0'), D_compaction('1') d0, d1 = D_compaction('0'), D_compaction('1')
``explore()`` ``explore()``
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
def explore(re): def explore(re):
@ -645,7 +645,7 @@ disappears once it has been matched.
return table, accepting return table, accepting
.. code:: ipython2 .. code:: python
table, accepting = explore(it) table, accepting = explore(it)
table table
@ -678,7 +678,7 @@ disappears once it has been matched.
.. code:: ipython2 .. code:: python
accepting accepting
@ -697,7 +697,7 @@ Generate Diagram
Once we have the FSM table and the set of accepting states we can Once we have the FSM table and the set of accepting states we can
generate the diagram above. generate the diagram above.
.. code:: ipython2 .. code:: python
_template = '''\ _template = '''\
digraph finite_state_machine { digraph finite_state_machine {
@ -722,7 +722,7 @@ generate the diagram above.
) )
) )
.. code:: ipython2 .. code:: python
print make_graph(table, accepting) print make_graph(table, accepting)
@ -776,7 +776,7 @@ Trampoline Function
Python has no GOTO statement but we can fake it with a “trampoline” Python has no GOTO statement but we can fake it with a “trampoline”
function. function.
.. code:: ipython2 .. code:: python
def trampoline(input_, jump_from, accepting): def trampoline(input_, jump_from, accepting):
I = iter(input_) I = iter(input_)
@ -793,7 +793,7 @@ Stream Functions
Little helpers to process the iterator of our data (a “stream” of “1” Little helpers to process the iterator of our data (a “stream” of “1”
and “0” characters, not bits.) and “0” characters, not bits.)
.. code:: ipython2 .. code:: python
getch = lambda I: int(next(I)) getch = lambda I: int(next(I))
@ -816,7 +816,7 @@ code. (You have to imagine that these are GOTO statements in C or
branches in assembly and that the state names are branch destination branches in assembly and that the state names are branch destination
labels.) labels.)
.. code:: ipython2 .. code:: python
a = lambda I: c if getch(I) else b a = lambda I: c if getch(I) else b
b = lambda I: _0(I) or d b = lambda I: _0(I) or d
@ -833,12 +833,12 @@ Note that the implementations of ``h`` and ``g`` are identical ergo
``h = g`` and we could eliminate one in the code but ``h`` is an ``h = g`` and we could eliminate one in the code but ``h`` is an
accepting state and ``g`` isnt. accepting state and ``g`` isnt.
.. code:: ipython2 .. code:: python
def acceptable(input_): def acceptable(input_):
return trampoline(input_, a, {h, i}) return trampoline(input_, a, {h, i})
.. code:: ipython2 .. code:: python
for n in range(2**5): for n in range(2**5):
s = bin(n)[2:] s = bin(n)[2:]

View File

@ -12,7 +12,7 @@ As an example of developing a program in Joy let's take the first problem from t
Find the sum of all the multiples of 3 or 5 below 1000. Find the sum of all the multiples of 3 or 5 below 1000.
.. code:: ipython2 .. code:: python
from notebook_preamble import J, V, define from notebook_preamble import J, V, define
@ -22,11 +22,11 @@ Sum a range filtered by a predicate
Let's create a predicate that returns ``True`` if a number is a multiple Let's create a predicate that returns ``True`` if a number is a multiple
of 3 or 5 and ``False`` otherwise. of 3 or 5 and ``False`` otherwise.
.. code:: ipython2 .. code:: python
define('P == [3 % not] dupdip 5 % not or') define('P == [3 % not] dupdip 5 % not or')
.. code:: ipython2 .. code:: python
V('80 P') V('80 P')
@ -108,11 +108,11 @@ the counter to the running sum. This function will do that:
PE1.1 == + [+] dupdip PE1.1 == + [+] dupdip
.. code:: ipython2 .. code:: python
define('PE1.1 == + [+] dupdip') define('PE1.1 == + [+] dupdip')
.. code:: ipython2 .. code:: python
V('0 0 3 PE1.1') V('0 0 3 PE1.1')
@ -131,7 +131,7 @@ the counter to the running sum. This function will do that:
3 3 . 3 3 .
.. code:: ipython2 .. code:: python
V('0 0 [3 2 1 3 1 2 3] [PE1.1] step') V('0 0 [3 2 1 3 1 2 3] [PE1.1] step')
@ -219,7 +219,7 @@ total to 60.
How many multiples to sum? How many multiples to sum?
^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code:: ipython2 .. code:: python
1000 / 15 1000 / 15
@ -232,7 +232,7 @@ How many multiples to sum?
.. code:: ipython2 .. code:: python
66 * 15 66 * 15
@ -245,7 +245,7 @@ How many multiples to sum?
.. code:: ipython2 .. code:: python
1000 - 990 1000 - 990
@ -260,7 +260,7 @@ How many multiples to sum?
We only want the terms *less than* 1000. We only want the terms *less than* 1000.
.. code:: ipython2 .. code:: python
999 - 990 999 - 990
@ -276,11 +276,11 @@ We only want the terms *less than* 1000.
That means we want to run the full list of numbers sixty-six times to That means we want to run the full list of numbers sixty-six times to
get to 990 and then the first four numbers 3 2 1 3 to get to 999. get to 990 and then the first four numbers 3 2 1 3 to get to 999.
.. code:: ipython2 .. code:: python
define('PE1 == 0 0 66 [[3 2 1 3 1 2 3] [PE1.1] step] times [3 2 1 3] [PE1.1] step pop') define('PE1 == 0 0 66 [[3 2 1 3 1 2 3] [PE1.1] step] times [3 2 1 3] [PE1.1] step pop')
.. code:: ipython2 .. code:: python
J('PE1') J('PE1')
@ -305,7 +305,7 @@ integer terms from the list.
3 2 1 3 1 2 3 3 2 1 3 1 2 3
0b 11 10 01 11 01 10 11 == 14811 0b 11 10 01 11 01 10 11 == 14811
.. code:: ipython2 .. code:: python
0b11100111011011 0b11100111011011
@ -318,11 +318,11 @@ integer terms from the list.
.. code:: ipython2 .. code:: python
define('PE1.2 == [3 & PE1.1] dupdip 2 >>') define('PE1.2 == [3 & PE1.1] dupdip 2 >>')
.. code:: ipython2 .. code:: python
V('0 0 14811 PE1.2') V('0 0 14811 PE1.2')
@ -349,7 +349,7 @@ integer terms from the list.
3 3 3702 . 3 3 3702 .
.. code:: ipython2 .. code:: python
V('3 3 3702 PE1.2') V('3 3 3702 PE1.2')
@ -376,7 +376,7 @@ integer terms from the list.
8 5 925 . 8 5 925 .
.. code:: ipython2 .. code:: python
V('0 0 14811 7 [PE1.2] times pop') V('0 0 14811 7 [PE1.2] times pop')
@ -518,11 +518,11 @@ integer terms from the list.
And so we have at last: And so we have at last:
.. code:: ipython2 .. code:: python
define('PE1 == 0 0 66 [14811 7 [PE1.2] times pop] times 14811 4 [PE1.2] times popop') define('PE1 == 0 0 66 [14811 7 [PE1.2] times pop] times 14811 4 [PE1.2] times popop')
.. code:: ipython2 .. code:: python
J('PE1') J('PE1')
@ -542,17 +542,17 @@ Let's refactor
14811 n [PE1.2] times pop 14811 n [PE1.2] times pop
n 14811 swap [PE1.2] times pop n 14811 swap [PE1.2] times pop
.. code:: ipython2 .. code:: python
define('PE1.3 == 14811 swap [PE1.2] times pop') define('PE1.3 == 14811 swap [PE1.2] times pop')
Now we can simplify the definition above: Now we can simplify the definition above:
.. code:: ipython2 .. code:: python
define('PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop') define('PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop')
.. code:: ipython2 .. code:: python
J('PE1') J('PE1')
@ -581,11 +581,11 @@ then four more. In the *Generator Programs* notebook we derive a
generator that can be repeatedly driven by the ``x`` combinator to generator that can be repeatedly driven by the ``x`` combinator to
produce a stream of the seven numbers repeating over and over again. produce a stream of the seven numbers repeating over and over again.
.. code:: ipython2 .. code:: python
define('PE1.terms == [0 swap [dup [pop 14811] [] branch [3 &] dupdip 2 >>] dip rest cons]') define('PE1.terms == [0 swap [dup [pop 14811] [] branch [3 &] dupdip 2 >>] dip rest cons]')
.. code:: ipython2 .. code:: python
J('PE1.terms 21 [x] times') J('PE1.terms 21 [x] times')
@ -598,7 +598,7 @@ produce a stream of the seven numbers repeating over and over again.
We know from above that we need sixty-six times seven then four more We know from above that we need sixty-six times seven then four more
terms to reach up to but not over one thousand. terms to reach up to but not over one thousand.
.. code:: ipython2 .. code:: python
J('7 66 * 4 +') J('7 66 * 4 +')
@ -611,7 +611,7 @@ terms to reach up to but not over one thousand.
Here they are... Here they are...
~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
J('PE1.terms 466 [x] times pop') J('PE1.terms 466 [x] times pop')
@ -624,7 +624,7 @@ Here they are...
...and they do sum to 999. ...and they do sum to 999.
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
J('[PE1.terms 466 [x] times pop] run sum') J('[PE1.terms 466 [x] times pop] run sum')
@ -638,7 +638,7 @@ Now we can use ``PE1.1`` to accumulate the terms as we go, and then
``pop`` the generator and the counter from the stack when we're done, ``pop`` the generator and the counter from the stack when we're done,
leaving just the sum. leaving just the sum.
.. code:: ipython2 .. code:: python
J('0 0 PE1.terms 466 [x [PE1.1] dip] times popop') J('0 0 PE1.terms 466 [x [PE1.1] dip] times popop')
@ -654,7 +654,7 @@ A little further analysis renders iteration unnecessary.
Consider finding the sum of the positive integers less than or equal to Consider finding the sum of the positive integers less than or equal to
ten. ten.
.. code:: ipython2 .. code:: python
J('[10 9 8 7 6 5 4 3 2 1] sum') J('[10 9 8 7 6 5 4 3 2 1] sum')
@ -686,11 +686,11 @@ positive integers is:
(The formula also works for odd values of N, I'll leave that to you if (The formula also works for odd values of N, I'll leave that to you if
you want to work it out or you can take my word for it.) you want to work it out or you can take my word for it.)
.. code:: ipython2 .. code:: python
define('F == dup ++ * 2 floordiv') define('F == dup ++ * 2 floordiv')
.. code:: ipython2 .. code:: python
V('10 F') V('10 F')
@ -727,7 +727,7 @@ And ending with:
If we reverse one of these two blocks and sum pairs... If we reverse one of these two blocks and sum pairs...
.. code:: ipython2 .. code:: python
J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip') J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip')
@ -737,7 +737,7 @@ If we reverse one of these two blocks and sum pairs...
[[978 15] [980 12] [981 10] [984 9] [985 6] [987 5] [990 3]] [[978 15] [980 12] [981 10] [984 9] [985 6] [987 5] [990 3]]
.. code:: ipython2 .. code:: python
J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map') J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map')
@ -750,7 +750,7 @@ If we reverse one of these two blocks and sum pairs...
(Interesting that the sequence of seven numbers appears again in the (Interesting that the sequence of seven numbers appears again in the
rightmost digit of each term.) rightmost digit of each term.)
.. code:: ipython2 .. code:: python
J('[ 3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map sum') J('[ 3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map sum')
@ -771,7 +771,7 @@ additional unpaired terms between 990 and 1000:
So we can give the "sum of all the multiples of 3 or 5 below 1000" like So we can give the "sum of all the multiples of 3 or 5 below 1000" like
so: so:
.. code:: ipython2 .. code:: python
J('6945 33 * [993 995 996 999] cons sum') J('6945 33 * [993 995 996 999] cons sum')

View File

@ -3,7 +3,7 @@ Using ``x`` to Generate Values
Cf. jp-reprod.html Cf. jp-reprod.html
.. code:: ipython2 .. code:: python
from notebook_preamble import J, V, define from notebook_preamble import J, V, define
@ -57,7 +57,7 @@ We can make a generator for the Natural numbers (0, 1, 2, …) by using
Lets try it: Lets try it:
.. code:: ipython2 .. code:: python
V('[0 swap [dup ++] dip rest cons] x') V('[0 swap [dup ++] dip rest cons] x')
@ -81,7 +81,7 @@ Lets try it:
After one application of ``x`` the quoted program contains ``1`` and After one application of ``x`` the quoted program contains ``1`` and
``0`` is below it on the stack. ``0`` is below it on the stack.
.. code:: ipython2 .. code:: python
J('[0 swap [dup ++] dip rest cons] x x x x x pop') J('[0 swap [dup ++] dip rest cons] x x x x x pop')
@ -94,11 +94,11 @@ After one application of ``x`` the quoted program contains ``1`` and
``direco`` ``direco``
---------- ----------
.. code:: ipython2 .. code:: python
define('direco == dip rest cons') define('direco == dip rest cons')
.. code:: ipython2 .. code:: python
V('[0 swap [dup ++] direco] x') V('[0 swap [dup ++] direco] x')
@ -149,13 +149,13 @@ Reading from the bottom up:
G == [direco] cons [swap] swap concat cons G == [direco] cons [swap] swap concat cons
G == [direco] cons [swap] swoncat cons G == [direco] cons [swap] swoncat cons
.. code:: ipython2 .. code:: python
define('G == [direco] cons [swap] swoncat cons') define('G == [direco] cons [swap] swoncat cons')
Lets try it out: Lets try it out:
.. code:: ipython2 .. code:: python
J('0 [dup ++] G') J('0 [dup ++] G')
@ -165,7 +165,7 @@ Lets try it out:
[0 swap [dup ++] direco] [0 swap [dup ++] direco]
.. code:: ipython2 .. code:: python
J('0 [dup ++] G x x x pop') J('0 [dup ++] G x x x pop')
@ -178,7 +178,7 @@ Lets try it out:
Powers of 2 Powers of 2
~~~~~~~~~~~ ~~~~~~~~~~~
.. code:: ipython2 .. code:: python
J('1 [dup 1 <<] G x x x x x x x x x pop') J('1 [dup 1 <<] G x x x x x x x x x pop')
@ -194,7 +194,7 @@ Powers of 2
If we have one of these quoted programs we can drive it using ``times`` If we have one of these quoted programs we can drive it using ``times``
with the ``x`` combinator. with the ``x`` combinator.
.. code:: ipython2 .. code:: python
J('23 [dup ++] G 5 [x] times') J('23 [dup ++] G 5 [x] times')
@ -226,11 +226,11 @@ int:
And pick them off by masking with 3 (binary 11) and then shifting the And pick them off by masking with 3 (binary 11) and then shifting the
int right two bits. int right two bits.
.. code:: ipython2 .. code:: python
define('PE1.1 == dup [3 &] dip 2 >>') define('PE1.1 == dup [3 &] dip 2 >>')
.. code:: ipython2 .. code:: python
V('14811 PE1.1') V('14811 PE1.1')
@ -252,7 +252,7 @@ int right two bits.
If we plug ``14811`` and ``[PE1.1]`` into our generator form… If we plug ``14811`` and ``[PE1.1]`` into our generator form…
.. code:: ipython2 .. code:: python
J('14811 [PE1.1] G') J('14811 [PE1.1] G')
@ -264,7 +264,7 @@ If we plug ``14811`` and ``[PE1.1]`` into our generator form…
…we get a generator that works for seven cycles before it reaches zero: …we get a generator that works for seven cycles before it reaches zero:
.. code:: ipython2 .. code:: python
J('[14811 swap [PE1.1] direco] 7 [x] times') J('[14811 swap [PE1.1] direco] 7 [x] times')
@ -280,11 +280,11 @@ Reset at Zero
We need a function that checks if the int has reached zero and resets it We need a function that checks if the int has reached zero and resets it
if so. if so.
.. code:: ipython2 .. code:: python
define('PE1.1.check == dup [pop 14811] [] branch') define('PE1.1.check == dup [pop 14811] [] branch')
.. code:: ipython2 .. code:: python
J('14811 [PE1.1.check PE1.1] G') J('14811 [PE1.1.check PE1.1] G')
@ -294,7 +294,7 @@ if so.
[14811 swap [PE1.1.check PE1.1] direco] [14811 swap [PE1.1.check PE1.1] direco]
.. code:: ipython2 .. code:: python
J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times') J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
@ -316,7 +316,7 @@ In the PE1 problem we are asked to sum all the multiples of three and
five less than 1000. Its worked out that we need to use all seven five less than 1000. Its worked out that we need to use all seven
numbers sixty-six times and then four more. numbers sixty-six times and then four more.
.. code:: ipython2 .. code:: python
J('7 66 * 4 +') J('7 66 * 4 +')
@ -328,7 +328,7 @@ numbers sixty-six times and then four more.
If we drive our generator 466 times and sum the stack we get 999. If we drive our generator 466 times and sum the stack we get 999.
.. code:: ipython2 .. code:: python
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times') J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times')
@ -338,7 +338,7 @@ If we drive our generator 466 times and sum the stack we get 999.
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] direco] 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] direco]
.. code:: ipython2 .. code:: python
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum') J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum')
@ -351,13 +351,13 @@ If we drive our generator 466 times and sum the stack we get 999.
Project Euler Problem One Project Euler Problem One
------------------------- -------------------------
.. code:: ipython2 .. code:: python
define('PE1.2 == + dup [+] dip') define('PE1.2 == + dup [+] dip')
Now we can add ``PE1.2`` to the quoted program given to ``G``. Now we can add ``PE1.2`` to the quoted program given to ``G``.
.. code:: ipython2 .. code:: python
J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop') J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop')
@ -445,15 +445,15 @@ Putting it all together:
F == + [popdd over] cons infra uncons F == + [popdd over] cons infra uncons
fib_gen == [1 1 F] fib_gen == [1 1 F]
.. code:: ipython2 .. code:: python
define('fib == + [popdd over] cons infra uncons') define('fib == + [popdd over] cons infra uncons')
.. code:: ipython2 .. code:: python
define('fib_gen == [1 1 fib]') define('fib_gen == [1 1 fib]')
.. code:: ipython2 .. code:: python
J('fib_gen 10 [x] times') J('fib_gen 10 [x] times')
@ -473,14 +473,14 @@ Now that we have a generator for the Fibonacci sequence, we need a
function that adds a term in the sequence to a sum if it is even, and function that adds a term in the sequence to a sum if it is even, and
``pop``\ s it otherwise. ``pop``\ s it otherwise.
.. code:: ipython2 .. code:: python
define('PE2.1 == dup 2 % [+] [pop] branch') define('PE2.1 == dup 2 % [+] [pop] branch')
And a predicate function that detects when the terms in the series And a predicate function that detects when the terms in the series
“exceed four million”. “exceed four million”.
.. code:: ipython2 .. code:: python
define('>4M == 4000000 >') define('>4M == 4000000 >')
@ -488,11 +488,11 @@ Now its straightforward to define ``PE2`` as a recursive function that
generates terms in the Fibonacci sequence until they exceed four million generates terms in the Fibonacci sequence until they exceed four million
and sums the even ones. and sums the even ones.
.. code:: ipython2 .. code:: python
define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec') define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec')
.. code:: ipython2 .. code:: python
J('PE2') J('PE2')
@ -535,7 +535,7 @@ So the Fibonacci sequence considered in terms of just parity would be:
Every third term is even. Every third term is even.
.. code:: ipython2 .. code:: python
J('[1 0 fib] x x x') # To start the sequence with 1 1 2 3 instead of 1 2 3. J('[1 0 fib] x x x') # To start the sequence with 1 1 2 3 instead of 1 2 3.
@ -547,7 +547,7 @@ Every third term is even.
Drive the generator three times and ``popop`` the two odd terms. Drive the generator three times and ``popop`` the two odd terms.
.. code:: ipython2 .. code:: python
J('[1 0 fib] x x x [popop] dipd') J('[1 0 fib] x x x [popop] dipd')
@ -557,11 +557,11 @@ Drive the generator three times and ``popop`` the two odd terms.
2 [3 2 fib] 2 [3 2 fib]
.. code:: ipython2 .. code:: python
define('PE2.2 == x x x [popop] dipd') define('PE2.2 == x x x [popop] dipd')
.. code:: ipython2 .. code:: python
J('[1 0 fib] 10 [PE2.2] times') J('[1 0 fib] 10 [PE2.2] times')
@ -574,7 +574,7 @@ Drive the generator three times and ``popop`` the two odd terms.
Replace ``x`` with our new driver function ``PE2.2`` and start our Replace ``x`` with our new driver function ``PE2.2`` and start our
``fib`` generator at ``1 0``. ``fib`` generator at ``1 0``.
.. code:: ipython2 .. code:: python
J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec') J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec')
@ -593,11 +593,11 @@ modifications to the default ``x``?
An Interesting Variation An Interesting Variation
------------------------ ------------------------
.. code:: ipython2 .. code:: python
define('codireco == cons dip rest cons') define('codireco == cons dip rest cons')
.. code:: ipython2 .. code:: python
V('[0 [dup ++] codireco] x') V('[0 [dup ++] codireco] x')
@ -620,11 +620,11 @@ An Interesting Variation
0 [1 [dup ++] codireco] . 0 [1 [dup ++] codireco] .
.. code:: ipython2 .. code:: python
define('G == [codireco] cons cons') define('G == [codireco] cons cons')
.. code:: ipython2 .. code:: python
J('230 [dup ++] G 5 [x] times pop') J('230 [dup ++] G 5 [x] times pop')

View File

@ -150,7 +150,7 @@ TBD (look in the :module: joy.parser module.)
Examples Examples
~~~~~~~~~~~ ~~~~~~~~~~~
.. code:: ipython2 .. code:: python
joy.parser.text_to_expression('1 2 3 4 5') # A simple sequence. joy.parser.text_to_expression('1 2 3 4 5') # A simple sequence.
@ -160,7 +160,7 @@ Examples
(1, (2, (3, (4, (5, ()))))) (1, (2, (3, (4, (5, ())))))
.. code:: ipython2 .. code:: python
joy.parser.text_to_expression('[1 2 3] 4 5') # Three items, the first is a list with three items joy.parser.text_to_expression('[1 2 3] 4 5') # Three items, the first is a list with three items
@ -170,7 +170,7 @@ Examples
((1, (2, (3, ()))), (4, (5, ()))) ((1, (2, (3, ()))), (4, (5, ())))
.. code:: ipython2 .. code:: python
joy.parser.text_to_expression('1 23 ["four" [-5.0] cons] 8888') # A mixed bag. cons is joy.parser.text_to_expression('1 23 ["four" [-5.0] cons] 8888') # A mixed bag. cons is
# a Symbol, no lookup at # a Symbol, no lookup at
@ -184,7 +184,7 @@ Examples
.. code:: ipython2 .. code:: python
joy.parser.text_to_expression('[][][][][]') # Five empty lists. joy.parser.text_to_expression('[][][][][]') # Five empty lists.
@ -197,7 +197,7 @@ Examples
.. code:: ipython2 .. code:: python
joy.parser.text_to_expression('[[[[[]]]]]') # Five nested lists. joy.parser.text_to_expression('[[[[[]]]]]') # Five nested lists.
@ -221,7 +221,7 @@ provide control-flow and higher-order operations.
Many of the functions are defined in Python, like ``dip``: Many of the functions are defined in Python, like ``dip``:
.. code:: ipython2 .. code:: python
print inspect.getsource(joy.library.dip) print inspect.getsource(joy.library.dip)
@ -239,7 +239,7 @@ When the interpreter executes a definition function that function just
pushes its body expression onto the pending expression (the pushes its body expression onto the pending expression (the
continuation) and returns control to the interpreter. continuation) and returns control to the interpreter.
.. code:: ipython2 .. code:: python
print joy.library.definitions print joy.library.definitions

View File

@ -36,7 +36,7 @@ implementation under the hood. (Where does the “type” come from? It has
a contingent existence predicated on the disciplined use of these a contingent existence predicated on the disciplined use of these
functions on otherwise undistinguished Joy datastructures.) functions on otherwise undistinguished Joy datastructures.)
.. code:: ipython2 .. code:: python
from notebook_preamble import D, J, V, define, DefinitionWrapper from notebook_preamble import D, J, V, define, DefinitionWrapper
@ -87,11 +87,11 @@ Definition:
Tree-new == swap [[] []] cons cons Tree-new == swap [[] []] cons cons
.. code:: ipython2 .. code:: python
define('Tree-new == swap [[] []] cons cons') define('Tree-new == swap [[] []] cons cons')
.. code:: ipython2 .. code:: python
J('"v" "k" Tree-new') J('"v" "k" Tree-new')
@ -163,11 +163,11 @@ comparison operator:
P < == pop roll> pop first < P < == pop roll> pop first <
P == pop roll> pop first P == pop roll> pop first
.. code:: ipython2 .. code:: python
define('P == pop roll> pop first') define('P == pop roll> pop first')
.. code:: ipython2 .. code:: python
J('["old_key" 23 [] []] 17 "new_key" ["..."] P') J('["old_key" 23 [] []] 17 "new_key" ["..."] P')
@ -242,11 +242,11 @@ And so ``T`` is just:
T == cons cons [dipdd] cons infra T == cons cons [dipdd] cons infra
.. code:: ipython2 .. code:: python
define('T == cons cons [dipdd] cons infra') define('T == cons cons [dipdd] cons infra')
.. code:: ipython2 .. code:: python
J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T') J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T')
@ -266,7 +266,7 @@ This is very very similar to the above:
[key_n value_n left right] value key [Tree-add] E [key_n value_n left right] value key [Tree-add] E
[key_n value_n left right] value key [Tree-add] [P <] [Te] [Ee] ifte [key_n value_n left right] value key [Tree-add] [P <] [Te] [Ee] ifte
.. code:: ipython2 .. code:: python
define('E == [P <] [Te] [Ee] ifte') define('E == [P <] [Te] [Ee] ifte')
@ -278,11 +278,11 @@ instead of the right, so the only difference is that it must use
Te == cons cons [dipd] cons infra Te == cons cons [dipd] cons infra
.. code:: ipython2 .. code:: python
define('Te == cons cons [dipd] cons infra') define('Te == cons cons [dipd] cons infra')
.. code:: ipython2 .. code:: python
J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te') J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te')
@ -320,11 +320,11 @@ Example:
key new_value [ left right] cons cons key new_value [ left right] cons cons
[key new_value left right] [key new_value left right]
.. code:: ipython2 .. code:: python
define('Ee == pop swap roll< rest rest cons cons') define('Ee == pop swap roll< rest rest cons cons')
.. code:: ipython2 .. code:: python
J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee') J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee')
@ -355,14 +355,14 @@ Putting it all together:
Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec
.. code:: ipython2 .. code:: python
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec') define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec')
Examples Examples
~~~~~~~~ ~~~~~~~~
.. code:: ipython2 .. code:: python
J('[] 23 "b" Tree-add') # Initial J('[] 23 "b" Tree-add') # Initial
@ -372,7 +372,7 @@ Examples
['b' 23 [] []] ['b' 23 [] []]
.. code:: ipython2 .. code:: python
J('["b" 23 [] []] 88 "c" Tree-add') # Greater than J('["b" 23 [] []] 88 "c" Tree-add') # Greater than
@ -382,7 +382,7 @@ Examples
['b' 23 [] ['c' 88 [] []]] ['b' 23 [] ['c' 88 [] []]]
.. code:: ipython2 .. code:: python
J('["b" 23 [] []] 88 "a" Tree-add') # Less than J('["b" 23 [] []] 88 "a" Tree-add') # Less than
@ -392,7 +392,7 @@ Examples
['b' 23 ['a' 88 [] []] []] ['b' 23 ['a' 88 [] []] []]
.. code:: ipython2 .. code:: python
J('["b" 23 [] []] 88 "b" Tree-add') # Equal to J('["b" 23 [] []] 88 "b" Tree-add') # Equal to
@ -402,7 +402,7 @@ Examples
['b' 88 [] []] ['b' 88 [] []]
.. code:: ipython2 .. code:: python
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Series. J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Series.
@ -412,7 +412,7 @@ Examples
['b' 23 ['a' 88 [] []] ['c' 44 [] []]] ['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
.. code:: ipython2 .. code:: python
J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step') J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step')
@ -444,7 +444,7 @@ values:
------------------------- a < b ------------------------- a < b
L L
.. code:: ipython2 .. code:: python
J("1 0 ['G'] ['E'] ['L'] cmp") J("1 0 ['G'] ['E'] ['L'] cmp")
@ -454,7 +454,7 @@ values:
'G' 'G'
.. code:: ipython2 .. code:: python
J("1 1 ['G'] ['E'] ['L'] cmp") J("1 1 ['G'] ['E'] ['L'] cmp")
@ -464,7 +464,7 @@ values:
'E' 'E'
.. code:: ipython2 .. code:: python
J("0 1 ['G'] ['E'] ['L'] cmp") J("0 1 ['G'] ['E'] ['L'] cmp")
@ -514,7 +514,7 @@ Or just:
P == over [popop popop first] nullary P == over [popop popop first] nullary
.. code:: ipython2 .. code:: python
define('P == over [popop popop first] nullary') define('P == over [popop popop first] nullary')
@ -541,11 +541,11 @@ to understand:
Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec
.. code:: ipython2 .. code:: python
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec') define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec')
.. code:: ipython2 .. code:: python
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Still works. J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Still works.
@ -685,14 +685,14 @@ Working backward:
Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec
.. code:: ipython2 .. code:: python
define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec') define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec')
Examples Examples
~~~~~~~~ ~~~~~~~~
.. code:: ipython2 .. code:: python
J('[] [foo] Tree-iter') # It doesn't matter what F is as it won't be used. J('[] [foo] Tree-iter') # It doesn't matter what F is as it won't be used.
@ -702,7 +702,7 @@ Examples
.. code:: ipython2 .. code:: python
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter") J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter")
@ -712,7 +712,7 @@ Examples
'b' 'a' 'c' 'b' 'a' 'c'
.. code:: ipython2 .. code:: python
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter") J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter")
@ -731,7 +731,7 @@ to it will only occur once within it, and we can query it in
`:math:`O(\log_2 N)` <https://en.wikipedia.org/wiki/Binary_search_tree#cite_note-2>`__ `:math:`O(\log_2 N)` <https://en.wikipedia.org/wiki/Binary_search_tree#cite_note-2>`__
time. time.
.. code:: ipython2 .. code:: python
J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step') J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step')
@ -741,11 +741,11 @@ time.
[3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]] [3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]]
.. code:: ipython2 .. code:: python
define('to_set == [] swap [0 swap Tree-add] step') define('to_set == [] swap [0 swap Tree-add] step')
.. code:: ipython2 .. code:: python
J('[3 9 5 2 8 6 7 8 4] to_set') J('[3 9 5 2 8 6 7 8 4] to_set')
@ -758,11 +758,11 @@ time.
And with that we can write a little program ``unique`` to remove And with that we can write a little program ``unique`` to remove
duplicate items from a list. duplicate items from a list.
.. code:: ipython2 .. code:: python
define('unique == [to_set [first] Tree-iter] cons run') define('unique == [to_set [first] Tree-iter] cons run')
.. code:: ipython2 .. code:: python
J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique') # Filter duplicate items. J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique') # Filter duplicate items.
@ -872,7 +872,7 @@ Lets do a little semantic factoring:
Now we can sort sequences. Now we can sort sequences.
.. code:: ipython2 .. code:: python
#define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec') #define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec')
@ -892,7 +892,7 @@ Now we can sort sequences.
.. code:: ipython2 .. code:: python
J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order') J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order')
@ -1070,7 +1070,7 @@ So:
Tree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec Tree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec
.. code:: ipython2 .. code:: python
# I don't want to deal with name conflicts with the above so I'm inlining everything here. # I don't want to deal with name conflicts with the above so I'm inlining everything here.
# The original Joy system has "hide" which is a meta-command which allows you to use named # The original Joy system has "hide" which is a meta-command which allows you to use named
@ -1088,7 +1088,7 @@ So:
] genrec ] genrec
''') ''')
.. code:: ipython2 .. code:: python
J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get') J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get')
@ -1098,7 +1098,7 @@ So:
'mike not in tree' 'mike not in tree'
.. code:: ipython2 .. code:: python
J('["gary" 23 [] []] "gary" [popop "err"] Tree-get') J('["gary" 23 [] []] "gary" [popop "err"] Tree-get')
@ -1108,7 +1108,7 @@ So:
23 23
.. code:: ipython2 .. code:: python
J(''' J('''
@ -1124,7 +1124,7 @@ So:
2 2
.. code:: ipython2 .. code:: python
J(''' J('''
@ -1500,7 +1500,7 @@ Refactoring
By the standards of the code Ive written so far, this is a *huge* Joy By the standards of the code Ive written so far, this is a *huge* Joy
program. program.
.. code:: ipython2 .. code:: python
DefinitionWrapper.add_definitions(''' DefinitionWrapper.add_definitions('''
first_two == uncons uncons pop first_two == uncons uncons pop
@ -1519,7 +1519,7 @@ program.
Tree-Delete == [pop not] [pop] [R0] [R1] genrec Tree-Delete == [pop not] [pop] [R0] [R1] genrec
''', D) ''', D)
.. code:: ipython2 .. code:: python
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ") J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ")
@ -1529,7 +1529,7 @@ program.
['a' 23 [] ['b' 88 [] []]] ['a' 23 [] ['b' 88 [] []]]
.. code:: ipython2 .. code:: python
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ") J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ")
@ -1539,7 +1539,7 @@ program.
['a' 23 [] ['c' 44 [] []]] ['a' 23 [] ['c' 44 [] []]]
.. code:: ipython2 .. code:: python
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ") J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ")
@ -1549,7 +1549,7 @@ program.
['b' 88 [] ['c' 44 [] []]] ['b' 88 [] ['c' 44 [] []]]
.. code:: ipython2 .. code:: python
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ") J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ")
@ -1559,7 +1559,7 @@ program.
['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] ['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
.. code:: ipython2 .. code:: python
J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step') J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step')
@ -1569,7 +1569,7 @@ program.
[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] [4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]]
.. code:: ipython2 .. code:: python
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ") J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ")
@ -1579,7 +1579,7 @@ program.
[4 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]] [4 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]]
.. code:: ipython2 .. code:: python
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ") J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ")

View File

@ -1,4 +1,4 @@
.. code:: ipython2 .. code:: python
from notebook_preamble import J, V, define from notebook_preamble import J, V, define
@ -81,13 +81,13 @@ the variables:
The three arguments are to the left, so we can “chop off” everything to The three arguments are to the left, so we can “chop off” everything to
the right and say its the definition of the ``quadratic`` function: the right and say its the definition of the ``quadratic`` function:
.. code:: ipython2 .. code:: python
define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2') define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
Lets try it out: Lets try it out:
.. code:: ipython2 .. code:: python
J('3 1 1 quadratic') J('3 1 1 quadratic')
@ -102,7 +102,7 @@ lines are the ``dip`` and ``dipd`` combinators building the main program
by incorporating the values on the stack. Then that program runs and you by incorporating the values on the stack. Then that program runs and you
get the results. This is pretty typical of Joy code. get the results. This is pretty typical of Joy code.
.. code:: ipython2 .. code:: python
V('-5 1 4 quadratic') V('-5 1 4 quadratic')

View File

@ -1,4 +1,4 @@
.. code:: ipython2 .. code:: python
from notebook_preamble import D, DefinitionWrapper, J, V, define from notebook_preamble import D, DefinitionWrapper, J, V, define
@ -80,7 +80,7 @@ is a recursive function ``H :: A -> C`` that converts a value of type
It may be helpful to see this function implemented in imperative Python It may be helpful to see this function implemented in imperative Python
code. code.
.. code:: ipython2 .. code:: python
def hylomorphism(c, F, P, G): def hylomorphism(c, F, P, G):
'''Return a hylomorphism function H.''' '''Return a hylomorphism function H.'''
@ -185,7 +185,7 @@ the left so we have a definition for ``hylomorphism``:
hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec
.. code:: ipython2 .. code:: python
define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec') define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')
@ -203,13 +203,13 @@ To sum a range of integers from 0 to *n* - 1:
- ``[G]`` is ``[-- dup]`` - ``[G]`` is ``[-- dup]``
- ``[F]`` is ``[+]`` - ``[F]`` is ``[+]``
.. code:: ipython2 .. code:: python
define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism') define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
Lets try it: Lets try it:
.. code:: ipython2 .. code:: python
J('5 triangular_number') J('5 triangular_number')
@ -219,7 +219,7 @@ Lets try it:
10 10
.. code:: ipython2 .. code:: python
J('[0 1 2 3 4 5 6] [triangular_number] map') J('[0 1 2 3 4 5 6] [triangular_number] map')
@ -405,11 +405,11 @@ Each of the above variations can be used to make four slightly different
H1 == [P] [pop c] [G] [dip F] genrec H1 == [P] [pop c] [G] [dip F] genrec
== [0 <=] [pop []] [-- dup] [dip swons] genrec == [0 <=] [pop []] [-- dup] [dip swons] genrec
.. code:: ipython2 .. code:: python
define('range == [0 <=] [] [-- dup] [swons] hylomorphism') define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
.. code:: ipython2 .. code:: python
J('5 range') J('5 range')
@ -427,11 +427,11 @@ Each of the above variations can be used to make four slightly different
H2 == c swap [P] [pop] [G [F] dip] primrec H2 == c swap [P] [pop] [G [F] dip] primrec
== [] swap [0 <=] [pop] [-- dup [swons] dip] primrec == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
.. code:: ipython2 .. code:: python
define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec') define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
.. code:: ipython2 .. code:: python
J('5 range_reverse') J('5 range_reverse')
@ -449,11 +449,11 @@ Each of the above variations can be used to make four slightly different
H3 == [P] [pop c] [[G] dupdip] [dip F] genrec H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
== [0 <=] [pop []] [[--] dupdip] [dip swons] genrec == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
.. code:: ipython2 .. code:: python
define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec') define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
.. code:: ipython2 .. code:: python
J('5 ranger') J('5 ranger')
@ -471,11 +471,11 @@ Each of the above variations can be used to make four slightly different
H4 == c swap [P] [pop] [[F] dupdip G ] primrec H4 == c swap [P] [pop] [[F] dupdip G ] primrec
== [] swap [0 <=] [pop] [[swons] dupdip --] primrec == [] swap [0 <=] [pop] [[swons] dupdip --] primrec
.. code:: ipython2 .. code:: python
define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec') define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
.. code:: ipython2 .. code:: python
J('5 ranger_reverse') J('5 ranger_reverse')
@ -501,7 +501,7 @@ and makes some new value.
C == [not] c [uncons swap] [F] hylomorphism C == [not] c [uncons swap] [F] hylomorphism
.. code:: ipython2 .. code:: python
define('swuncons == uncons swap') # Awkward name. define('swuncons == uncons swap') # Awkward name.
@ -511,11 +511,11 @@ An example of a catamorphism is the sum function.
sum == [not] 0 [swuncons] [+] hylomorphism sum == [not] 0 [swuncons] [+] hylomorphism
.. code:: ipython2 .. code:: python
define('sum == [not] 0 [swuncons] [+] hylomorphism') define('sum == [not] 0 [swuncons] [+] hylomorphism')
.. code:: ipython2 .. code:: python
J('[5 4 3 2 1] sum') J('[5 4 3 2 1] sum')
@ -531,7 +531,7 @@ The ``step`` combinator
The ``step`` combinator will usually be better to use than The ``step`` combinator will usually be better to use than
``catamorphism``. ``catamorphism``.
.. code:: ipython2 .. code:: python
J('[step] help') J('[step] help')
@ -560,11 +560,11 @@ The ``step`` combinator will usually be better to use than
.. code:: ipython2 .. code:: python
define('sum == 0 swap [+] step') define('sum == 0 swap [+] step')
.. code:: ipython2 .. code:: python
J('[5 4 3 2 1] sum') J('[5 4 3 2 1] sum')
@ -592,11 +592,11 @@ With:
G == -- G == --
P == 1 <= P == 1 <=
.. code:: ipython2 .. code:: python
define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec') define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
.. code:: ipython2 .. code:: python
J('5 factorial') J('5 factorial')
@ -635,11 +635,11 @@ We would use:
G == rest dup G == rest dup
P == not P == not
.. code:: ipython2 .. code:: python
define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec') define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
.. code:: ipython2 .. code:: python
J('[1 2 3] tails') J('[1 2 3] tails')

View File

@ -9,14 +9,14 @@ dictionary. However, theres no function that does that. Adding a new
function to the dictionary is a meta-interpreter action, you have to do function to the dictionary is a meta-interpreter action, you have to do
it in Python, not Joy. it in Python, not Joy.
.. code:: ipython2 .. code:: python
from notebook_preamble import D, J, V from notebook_preamble import D, J, V
A long trace A long trace
------------ ------------
.. code:: ipython2 .. code:: python
V('[23 18] average') V('[23 18] average')
@ -81,7 +81,7 @@ An efficient ``sum`` function is already in the library. But for
``size`` we can use a “compiled” version hand-written in Python to speed ``size`` we can use a “compiled” version hand-written in Python to speed
up evaluation and make the trace more readable. up evaluation and make the trace more readable.
.. code:: ipython2 .. code:: python
from joy.library import SimpleFunctionWrapper from joy.library import SimpleFunctionWrapper
from joy.utils.stack import iter_stack from joy.utils.stack import iter_stack
@ -99,7 +99,7 @@ up evaluation and make the trace more readable.
Now we replace the old version in the dictionary with the new version, Now we replace the old version in the dictionary with the new version,
and re-evaluate the expression. and re-evaluate the expression.
.. code:: ipython2 .. code:: python
D['size'] = size D['size'] = size
@ -108,7 +108,7 @@ A shorter trace
You can see that ``size`` now executes in a single step. You can see that ``size`` now executes in a single step.
.. code:: ipython2 .. code:: python
V('[23 18] average') V('[23 18] average')

View File

@ -148,11 +148,11 @@ Working backwards:
Define ``treestep`` Define ``treestep``
------------------- -------------------
.. code:: ipython2 .. code:: python
from notebook_preamble import D, J, V, define, DefinitionWrapper from notebook_preamble import D, J, V, define, DefinitionWrapper
.. code:: ipython2 .. code:: python
DefinitionWrapper.add_definitions(''' DefinitionWrapper.add_definitions('''
@ -173,7 +173,7 @@ all nodes in a tree with this function:
sumtree == [pop 0] [] [sum +] treestep sumtree == [pop 0] [] [sum +] treestep
.. code:: ipython2 .. code:: python
define('sumtree == [pop 0] [] [sum +] treestep') define('sumtree == [pop 0] [] [sum +] treestep')
@ -185,7 +185,7 @@ Running this function on an empty tree value gives zero:
------------------------------------ ------------------------------------
0 0
.. code:: ipython2 .. code:: python
J('[] sumtree') # Empty tree. J('[] sumtree') # Empty tree.
@ -205,7 +205,7 @@ Running it on a non-empty node:
n m + n m +
n+m n+m
.. code:: ipython2 .. code:: python
J('[23] sumtree') # No child trees. J('[23] sumtree') # No child trees.
@ -215,7 +215,7 @@ Running it on a non-empty node:
23 23
.. code:: ipython2 .. code:: python
J('[23 []] sumtree') # Child tree, empty. J('[23 []] sumtree') # Child tree, empty.
@ -225,7 +225,7 @@ Running it on a non-empty node:
23 23
.. code:: ipython2 .. code:: python
J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees. J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees.
@ -235,7 +235,7 @@ Running it on a non-empty node:
32 32
.. code:: ipython2 .. code:: python
J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc... J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc...
@ -245,7 +245,7 @@ Running it on a non-empty node:
49 49
.. code:: ipython2 .. code:: python
J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate "spelling". J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate "spelling".
@ -255,7 +255,7 @@ Running it on a non-empty node:
49 49
.. code:: ipython2 .. code:: python
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep') # Replace each node. J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep') # Replace each node.
@ -265,7 +265,7 @@ Running it on a non-empty node:
[23 [23 [23] [23]] [23] [23 []]] [23 [23 [23] [23]] [23] [23 []]]
.. code:: ipython2 .. code:: python
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep') J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep')
@ -275,7 +275,7 @@ Running it on a non-empty node:
[1 [1 [1] [1]] [1] [1 []]] [1 [1 [1] [1]] [1] [1 []]]
.. code:: ipython2 .. code:: python
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree') J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree')
@ -285,7 +285,7 @@ Running it on a non-empty node:
6 6
.. code:: ipython2 .. code:: python
J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function. J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
@ -295,7 +295,7 @@ Running it on a non-empty node:
6 6
.. code:: ipython2 .. code:: python
J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function. J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
@ -339,7 +339,7 @@ Traversal
This doesnt quite work: This doesnt quite work:
.. code:: ipython2 .. code:: python
J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep') J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep')
@ -369,7 +369,7 @@ So:
[] [first] [flatten cons] treestep [] [first] [flatten cons] treestep
.. code:: ipython2 .. code:: python
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first] [flatten cons] treestep') J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first] [flatten cons] treestep')
@ -401,7 +401,7 @@ So:
[] [i roll< swons concat] [first] treestep [] [i roll< swons concat] [first] treestep
.. code:: ipython2 .. code:: python
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [uncons pop] [i roll< swons concat] treestep') J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [uncons pop] [i roll< swons concat] treestep')
@ -429,7 +429,7 @@ Plugging in our BTree structure:
[key value] N [left right] [K] C [key value] N [left right] [K] C
.. code:: ipython2 .. code:: python
J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind') J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
@ -444,7 +444,7 @@ Plugging in our BTree structure:
Iteration through the nodes Iteration through the nodes
.. code:: ipython2 .. code:: python
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] ["N"] [step] treegrind') J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] ["N"] [step] treegrind')
@ -456,7 +456,7 @@ Iteration through the nodes
Sum the nodes keys. Sum the nodes keys.
.. code:: ipython2 .. code:: python
J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind') J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind')
@ -468,7 +468,7 @@ Sum the nodes keys.
Rebuild the tree using ``map`` (imitating ``treestep``.) Rebuild the tree using ``map`` (imitating ``treestep``.)
.. code:: ipython2 .. code:: python
J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind') J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind')
@ -574,7 +574,7 @@ Putting it together
To me, that seems simpler than the ``genrec`` version. To me, that seems simpler than the ``genrec`` version.
.. code:: ipython2 .. code:: python
DefinitionWrapper.add_definitions(''' DefinitionWrapper.add_definitions('''
@ -587,7 +587,7 @@ To me, that seems simpler than the ``genrec`` version.
''', D) ''', D)
.. code:: ipython2 .. code:: python
J('''\ J('''\
@ -603,7 +603,7 @@ To me, that seems simpler than the ``genrec`` version.
15 15
.. code:: ipython2 .. code:: python
J('''\ J('''\

View File

@ -1,7 +1,7 @@
Type Checking Type Checking
============= =============
.. code:: ipython2 .. code:: python
import logging, sys import logging, sys
@ -11,7 +11,7 @@ Type Checking
level=logging.INFO, level=logging.INFO,
) )
.. code:: ipython2 .. code:: python
from joy.utils.types import ( from joy.utils.types import (
doc_from_stack_effect, doc_from_stack_effect,
@ -22,7 +22,7 @@ Type Checking
JoyTypeError, JoyTypeError,
) )
.. code:: ipython2 .. code:: python
D = FUNCTIONS.copy() D = FUNCTIONS.copy()
del D['product'] del D['product']
@ -31,7 +31,7 @@ Type Checking
An Example An Example
---------- ----------
.. code:: ipython2 .. code:: python
fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0] fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0]
@ -46,7 +46,7 @@ An Example
40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘ 40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘
.. code:: ipython2 .. code:: python
print doc_from_stack_effect(fi, fo) print doc_from_stack_effect(fi, fo)
@ -56,13 +56,13 @@ An Example
([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
.. code:: ipython2 .. code:: python
from joy.parser import text_to_expression from joy.parser import text_to_expression
from joy.utils.stack import stack_to_string from joy.utils.stack import stack_to_string
.. code:: ipython2 .. code:: python
e = text_to_expression('0 1 2 [3 4]') # reverse order e = text_to_expression('0 1 2 [3 4]') # reverse order
print stack_to_string(e) print stack_to_string(e)
@ -73,7 +73,7 @@ An Example
[3 4] 2 1 0 [3 4] 2 1 0
.. code:: ipython2 .. code:: python
u = unify(e, fi)[0] u = unify(e, fi)[0]
u u
@ -87,7 +87,7 @@ An Example
.. code:: ipython2 .. code:: python
g = reify(u, (fi, fo)) g = reify(u, (fi, fo))
print doc_from_stack_effect(*g) print doc_from_stack_effect(*g)
@ -101,11 +101,11 @@ An Example
Unification Works “in Reverse” Unification Works “in Reverse”
------------------------------ ------------------------------
.. code:: ipython2 .. code:: python
e = text_to_expression('[2 3]') e = text_to_expression('[2 3]')
.. code:: ipython2 .. code:: python
u = unify(e, fo)[0] # output side, not input side u = unify(e, fo)[0] # output side, not input side
u u
@ -119,7 +119,7 @@ Unification Works “in Reverse”
.. code:: ipython2 .. code:: python
g = reify(u, (fi, fo)) g = reify(u, (fi, fo))
print doc_from_stack_effect(*g) print doc_from_stack_effect(*g)
@ -133,7 +133,7 @@ Unification Works “in Reverse”
Failing a Check Failing a Check
--------------- ---------------
.. code:: ipython2 .. code:: python
fi, fo = infer(dup, mul)[0] fi, fo = infer(dup, mul)[0]
@ -146,7 +146,7 @@ Failing a Check
31 (i1 -- i2) ∘ 31 (i1 -- i2) ∘
.. code:: ipython2 .. code:: python
e = text_to_expression('"two"') e = text_to_expression('"two"')
print stack_to_string(e) print stack_to_string(e)
@ -157,7 +157,7 @@ Failing a Check
'two' 'two'
.. code:: ipython2 .. code:: python
try: try:
unify(e, fi) unify(e, fi)

View File

@ -184,7 +184,7 @@ Compiling ``pop∘swap∘roll<``
The simplest way to “compile” this function would be something like: The simplest way to “compile” this function would be something like:
.. code:: ipython2 .. code:: python
def poswrd(s, e, d): def poswrd(s, e, d):
return rolldown(*swap(*pop(s, e, d))) return rolldown(*swap(*pop(s, e, d)))
@ -200,7 +200,7 @@ Looking ahead for a moment, from the stack effect comment:
We should be able to directly write out a Python function like: We should be able to directly write out a Python function like:
.. code:: ipython2 .. code:: python
def poswrd(stack): def poswrd(stack):
(_, (a, (b, (c, stack)))) = stack (_, (a, (b, (c, stack)))) = stack
@ -393,7 +393,7 @@ And there you have it, the stack effect for
From this stack effect comment it should be possible to construct the From this stack effect comment it should be possible to construct the
following Python code: following Python code:
.. code:: ipython2 .. code:: python
def F(stack): def F(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack (_, (d, (c, ((a, (b, S0)), stack)))) = stack
@ -408,7 +408,7 @@ Representing Stack Effect Comments in Python
Im going to use pairs of tuples of type descriptors, which will be Im going to use pairs of tuples of type descriptors, which will be
integers or tuples of type descriptors: integers or tuples of type descriptors:
.. code:: ipython2 .. code:: python
roll_dn = (1, 2, 3), (2, 3, 1) roll_dn = (1, 2, 3), (2, 3, 1)
@ -419,7 +419,7 @@ integers or tuples of type descriptors:
``compose()`` ``compose()``
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
def compose(f, g): def compose(f, g):
@ -465,7 +465,7 @@ integers or tuples of type descriptors:
``unify()`` ``unify()``
~~~~~~~~~~~ ~~~~~~~~~~~
.. code:: ipython2 .. code:: python
def unify(u, v, s=None): def unify(u, v, s=None):
if s is None: if s is None:
@ -483,7 +483,7 @@ integers or tuples of type descriptors:
``update()`` ``update()``
~~~~~~~~~~~~ ~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
def update(s, term): def update(s, term):
if not isinstance(term, tuple): if not isinstance(term, tuple):
@ -493,7 +493,7 @@ integers or tuples of type descriptors:
``relabel()`` ``relabel()``
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
def relabel(left, right): def relabel(left, right):
return left, _1000(right) return left, _1000(right)
@ -517,7 +517,7 @@ integers or tuples of type descriptors:
``delabel()`` ``delabel()``
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
def delabel(f): def delabel(f):
s = {u: i for i, u in enumerate(sorted(_unique(f)))} s = {u: i for i, u in enumerate(sorted(_unique(f)))}
@ -551,7 +551,7 @@ At last we put it all together in a function ``C()`` that accepts two
stack effect comments and returns their composition (or raises and stack effect comments and returns their composition (or raises and
exception if they cant be composed due to type conflicts.) exception if they cant be composed due to type conflicts.)
.. code:: ipython2 .. code:: python
def C(f, g): def C(f, g):
f, g = relabel(f, g) f, g = relabel(f, g)
@ -560,7 +560,7 @@ exception if they cant be composed due to type conflicts.)
Lets try it out. Lets try it out.
.. code:: ipython2 .. code:: python
C(pop, swap) C(pop, swap)
@ -573,7 +573,7 @@ Lets try it out.
.. code:: ipython2 .. code:: python
C(C(pop, swap), roll_dn) C(C(pop, swap), roll_dn)
@ -586,7 +586,7 @@ Lets try it out.
.. code:: ipython2 .. code:: python
C(swap, roll_dn) C(swap, roll_dn)
@ -599,7 +599,7 @@ Lets try it out.
.. code:: ipython2 .. code:: python
C(pop, C(swap, roll_dn)) C(pop, C(swap, roll_dn))
@ -612,7 +612,7 @@ Lets try it out.
.. code:: ipython2 .. code:: python
poswrd = reduce(C, (pop, swap, roll_dn)) poswrd = reduce(C, (pop, swap, roll_dn))
poswrd poswrd
@ -633,13 +633,13 @@ Heres that trick to represent functions like ``rest`` and ``cons`` that
manipulate stacks. We use a cons-list of tuples and give the tails their manipulate stacks. We use a cons-list of tuples and give the tails their
own numbers. Then everything above already works. own numbers. Then everything above already works.
.. code:: ipython2 .. code:: python
rest = ((1, 2),), (2,) rest = ((1, 2),), (2,)
cons = (1, 2), ((1, 2),) cons = (1, 2), ((1, 2),)
.. code:: ipython2 .. code:: python
C(poswrd, rest) C(poswrd, rest)
@ -671,7 +671,7 @@ The translation table, if you will, would be:
0: 0, 0: 0,
} }
.. code:: ipython2 .. code:: python
F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons)) F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
@ -699,11 +699,11 @@ Dealing with ``cons`` and ``uncons``
However, if we try to compose e.g. ``cons`` and ``uncons`` it wont However, if we try to compose e.g. ``cons`` and ``uncons`` it wont
work: work:
.. code:: ipython2 .. code:: python
uncons = ((1, 2),), (1, 2) uncons = ((1, 2),), (1, 2)
.. code:: ipython2 .. code:: python
try: try:
C(cons, uncons) C(cons, uncons)
@ -723,7 +723,7 @@ The problem is that the ``unify()`` function as written doesnt handle
the case when both terms are tuples. We just have to add a clause to the case when both terms are tuples. We just have to add a clause to
deal with this recursively: deal with this recursively:
.. code:: ipython2 .. code:: python
def unify(u, v, s=None): def unify(u, v, s=None):
if s is None: if s is None:
@ -753,7 +753,7 @@ deal with this recursively:
return s return s
.. code:: ipython2 .. code:: python
C(cons, uncons) C(cons, uncons)
@ -771,7 +771,7 @@ Part III: Compiling Yin Functions
Now consider the Python function we would like to derive: Now consider the Python function we would like to derive:
.. code:: ipython2 .. code:: python
def F_python(stack): def F_python(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack (_, (d, (c, ((a, (b, S0)), stack)))) = stack
@ -779,7 +779,7 @@ Now consider the Python function we would like to derive:
And compare it to the input stack effect comment tuple we just computed: And compare it to the input stack effect comment tuple we just computed:
.. code:: ipython2 .. code:: python
F[0] F[0]
@ -816,7 +816,7 @@ Eh?
And the return tuple And the return tuple
.. code:: ipython2 .. code:: python
F[1] F[1]
@ -848,7 +848,7 @@ Python Identifiers
We want to substitute Python identifiers for the integers. Im going to We want to substitute Python identifiers for the integers. Im going to
repurpose ``joy.parser.Symbol`` class for this: repurpose ``joy.parser.Symbol`` class for this:
.. code:: ipython2 .. code:: python
from collections import defaultdict from collections import defaultdict
from joy.parser import Symbol from joy.parser import Symbol
@ -874,7 +874,7 @@ effect comment tuples to reasonable text format. There are some details
in how this code works that related to stuff later in the notebook, so in how this code works that related to stuff later in the notebook, so
you should skip it for now and read it later if youre interested. you should skip it for now and read it later if youre interested.
.. code:: ipython2 .. code:: python
def doc_from_stack_effect(inputs, outputs): def doc_from_stack_effect(inputs, outputs):
return '(%s--%s)' % ( return '(%s--%s)' % (
@ -914,7 +914,7 @@ Now we can write a compiler function to emit Python source code. (The
underscore suffix distiguishes it from the built-in ``compile()`` underscore suffix distiguishes it from the built-in ``compile()``
function.) function.)
.. code:: ipython2 .. code:: python
def compile_(name, f, doc=None): def compile_(name, f, doc=None):
if doc is None: if doc is None:
@ -932,7 +932,7 @@ function.)
Here it is in action: Here it is in action:
.. code:: ipython2 .. code:: python
source = compile_('F', F) source = compile_('F', F)
@ -949,7 +949,7 @@ Here it is in action:
Compare: Compare:
.. code:: ipython2 .. code:: python
def F_python(stack): def F_python(stack):
(_, (d, (c, ((a, (b, S0)), stack)))) = stack (_, (d, (c, ((a, (b, S0)), stack)))) = stack
@ -957,7 +957,7 @@ Compare:
Next steps: Next steps:
.. code:: ipython2 .. code:: python
L = {} L = {}
@ -976,16 +976,16 @@ Next steps:
Lets try it out: Lets try it out:
.. code:: ipython2 .. code:: python
from notebook_preamble import D, J, V from notebook_preamble import D, J, V
from joy.library import SimpleFunctionWrapper from joy.library import SimpleFunctionWrapper
.. code:: ipython2 .. code:: python
D['F'] = SimpleFunctionWrapper(L['F']) D['F'] = SimpleFunctionWrapper(L['F'])
.. code:: ipython2 .. code:: python
J('[4 5 ...] 2 3 1 F') J('[4 5 ...] 2 3 1 F')
@ -1012,7 +1012,7 @@ Compiling Library Functions
We can use ``compile_()`` to generate many primitives in the library We can use ``compile_()`` to generate many primitives in the library
from their stack effect comments: from their stack effect comments:
.. code:: ipython2 .. code:: python
def defs(): def defs():
@ -1036,7 +1036,7 @@ from their stack effect comments:
return locals() return locals()
.. code:: ipython2 .. code:: python
for name, stack_effect_comment in sorted(defs().items()): for name, stack_effect_comment in sorted(defs().items()):
print print
@ -1205,7 +1205,7 @@ Python class hierarchy of Joy types and use the ``issubclass()`` method
to establish domain ordering, as well as other handy behaviour that will to establish domain ordering, as well as other handy behaviour that will
make it fairly easy to reuse most of the code above. make it fairly easy to reuse most of the code above.
.. code:: ipython2 .. code:: python
class AnyJoyType(object): class AnyJoyType(object):
@ -1251,14 +1251,14 @@ make it fairly easy to reuse most of the code above.
Mess with it a little: Mess with it a little:
.. code:: ipython2 .. code:: python
from itertools import permutations from itertools import permutations
“Any” types can be specialized to numbers and stacks, but not vice “Any” types can be specialized to numbers and stacks, but not vice
versa: versa:
.. code:: ipython2 .. code:: python
for a, b in permutations((A[0], N[0], S[0]), 2): for a, b in permutations((A[0], N[0], S[0]), 2):
print a, '>=', b, '->', a >= b print a, '>=', b, '->', a >= b
@ -1278,7 +1278,7 @@ Our crude `Numerical
Tower <https://en.wikipedia.org/wiki/Numerical_tower>`__ of *numbers* > Tower <https://en.wikipedia.org/wiki/Numerical_tower>`__ of *numbers* >
*floats* > *integers* works as well (but were not going to use it yet): *floats* > *integers* works as well (but were not going to use it yet):
.. code:: ipython2 .. code:: python
for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2): for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
print a, '>=', b, '->', a >= b print a, '>=', b, '->', a >= b
@ -1303,13 +1303,13 @@ Tower <https://en.wikipedia.org/wiki/Numerical_tower>`__ of *numbers* >
Typing ``sqr`` Typing ``sqr``
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
.. code:: ipython2 .. code:: python
dup = (A[1],), (A[1], A[1]) dup = (A[1],), (A[1], A[1])
mul = (N[1], N[2]), (N[3],) mul = (N[1], N[2]), (N[3],)
.. code:: ipython2 .. code:: python
dup dup
@ -1322,7 +1322,7 @@ Typing ``sqr``
.. code:: ipython2 .. code:: python
mul mul
@ -1340,7 +1340,7 @@ Modifying the Inferencer
Re-labeling still works fine: Re-labeling still works fine:
.. code:: ipython2 .. code:: python
foo = relabel(dup, mul) foo = relabel(dup, mul)
@ -1361,7 +1361,7 @@ Re-labeling still works fine:
The ``delabel()`` function needs an overhaul. It now has to keep track The ``delabel()`` function needs an overhaul. It now has to keep track
of how many labels of each domain it has “seen”. of how many labels of each domain it has “seen”.
.. code:: ipython2 .. code:: python
from collections import Counter from collections import Counter
@ -1383,7 +1383,7 @@ of how many labels of each domain it has “seen”.
return tuple(delabel(inner, seen, c) for inner in f) return tuple(delabel(inner, seen, c) for inner in f)
.. code:: ipython2 .. code:: python
delabel(foo) delabel(foo)
@ -1399,7 +1399,7 @@ of how many labels of each domain it has “seen”.
``unify()`` version 3 ``unify()`` version 3
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
.. code:: ipython2 .. code:: python
def unify(u, v, s=None): def unify(u, v, s=None):
if s is None: if s is None:
@ -1449,7 +1449,7 @@ of how many labels of each domain it has “seen”.
Rewrite the stack effect comments: Rewrite the stack effect comments:
.. code:: ipython2 .. code:: python
def defs(): def defs():
@ -1503,11 +1503,11 @@ Rewrite the stack effect comments:
return locals() return locals()
.. code:: ipython2 .. code:: python
DEFS = defs() DEFS = defs()
.. code:: ipython2 .. code:: python
for name, stack_effect_comment in sorted(DEFS.items()): for name, stack_effect_comment in sorted(DEFS.items()):
print name, '=', doc_from_stack_effect(*stack_effect_comment) print name, '=', doc_from_stack_effect(*stack_effect_comment)
@ -1543,14 +1543,14 @@ Rewrite the stack effect comments:
uncons = ([a1 .1.] -- a1 [.1.]) uncons = ([a1 .1.] -- a1 [.1.])
.. code:: ipython2 .. code:: python
globals().update(DEFS) globals().update(DEFS)
Compose ``dup`` and ``mul`` Compose ``dup`` and ``mul``
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code:: ipython2 .. code:: python
C(dup, mul) C(dup, mul)
@ -1565,7 +1565,7 @@ Compose ``dup`` and ``mul``
Revisit the ``F`` function, works fine. Revisit the ``F`` function, works fine.
.. code:: ipython2 .. code:: python
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons)) F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
F F
@ -1579,7 +1579,7 @@ Revisit the ``F`` function, works fine.
.. code:: ipython2 .. code:: python
print doc_from_stack_effect(*F) print doc_from_stack_effect(*F)
@ -1592,12 +1592,12 @@ Revisit the ``F`` function, works fine.
Some otherwise inefficient functions are no longer to be feared. We can Some otherwise inefficient functions are no longer to be feared. We can
also get the effect of combinators in some limited cases. also get the effect of combinators in some limited cases.
.. code:: ipython2 .. code:: python
def neato(*funcs): def neato(*funcs):
print doc_from_stack_effect(*reduce(C, funcs)) print doc_from_stack_effect(*reduce(C, funcs))
.. code:: ipython2 .. code:: python
# e.g. [swap] dip # e.g. [swap] dip
neato(rollup, swap, rolldown) neato(rollup, swap, rolldown)
@ -1608,7 +1608,7 @@ also get the effect of combinators in some limited cases.
(a1 a2 a3 -- a2 a1 a3) (a1 a2 a3 -- a2 a1 a3)
.. code:: ipython2 .. code:: python
# e.g. [popop] dipd # e.g. [popop] dipd
neato(popdd, rolldown, pop) neato(popdd, rolldown, pop)
@ -1619,7 +1619,7 @@ also get the effect of combinators in some limited cases.
(a1 a2 a3 a4 -- a3 a4) (a1 a2 a3 a4 -- a3 a4)
.. code:: ipython2 .. code:: python
# Reverse the order of the top three items. # Reverse the order of the top three items.
neato(rollup, swap) neato(rollup, swap)
@ -1636,7 +1636,7 @@ also get the effect of combinators in some limited cases.
Because the type labels represent themselves as valid Python identifiers Because the type labels represent themselves as valid Python identifiers
the ``compile_()`` function doesnt need to generate them anymore: the ``compile_()`` function doesnt need to generate them anymore:
.. code:: ipython2 .. code:: python
def compile_(name, f, doc=None): def compile_(name, f, doc=None):
inputs, outputs = f inputs, outputs = f
@ -1652,7 +1652,7 @@ the ``compile_()`` function doesnt need to generate them anymore:
%s = stack %s = stack
return %s''' % (name, doc, i, o) return %s''' % (name, doc, i, o)
.. code:: ipython2 .. code:: python
print compile_('F', F) print compile_('F', F)
@ -1668,7 +1668,7 @@ the ``compile_()`` function doesnt need to generate them anymore:
But it cannot magically create new functions that involve e.g. math and But it cannot magically create new functions that involve e.g. math and
such. Note that this is *not* a ``sqr`` function implementation: such. Note that this is *not* a ``sqr`` function implementation:
.. code:: ipython2 .. code:: python
print compile_('sqr', C(dup, mul)) print compile_('sqr', C(dup, mul))
@ -1696,7 +1696,7 @@ The functions that *can* be compiled are the ones that have only
``AnyJoyType`` and ``StackJoyType`` labels in their stack effect ``AnyJoyType`` and ``StackJoyType`` labels in their stack effect
comments. We can write a function to check that: comments. We can write a function to check that:
.. code:: ipython2 .. code:: python
from itertools import imap from itertools import imap
@ -1704,7 +1704,7 @@ comments. We can write a function to check that:
def compilable(f): def compilable(f):
return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f) return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f)
.. code:: ipython2 .. code:: python
for name, stack_effect_comment in sorted(defs().items()): for name, stack_effect_comment in sorted(defs().items()):
if compilable(stack_effect_comment): if compilable(stack_effect_comment):
@ -1828,7 +1828,7 @@ the “truthiness” of ``StackJoyType`` to false to let e.g.
``joy.utils.stack.concat`` work with our stack effect comment cons-list ``joy.utils.stack.concat`` work with our stack effect comment cons-list
tuples.) tuples.)
.. code:: ipython2 .. code:: python
def compose(f, g): def compose(f, g):
(f_in, f_out), (g_in, g_out) = f, g (f_in, f_out), (g_in, g_out) = f, g
@ -1840,7 +1840,7 @@ tuples.)
I dont want to rewrite all the defs myself, so Ill write a little I dont want to rewrite all the defs myself, so Ill write a little
conversion function instead. This is programmers laziness. conversion function instead. This is programmers laziness.
.. code:: ipython2 .. code:: python
def sequence_to_stack(seq, stack=StackJoyType(23)): def sequence_to_stack(seq, stack=StackJoyType(23)):
for item in seq: stack = item, stack for item in seq: stack = item, stack
@ -1854,7 +1854,7 @@ conversion function instead. This is programmers laziness.
NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1]) NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1])
globals().update(NEW_DEFS) globals().update(NEW_DEFS)
.. code:: ipython2 .. code:: python
C(stack, uncons) C(stack, uncons)
@ -1867,7 +1867,7 @@ conversion function instead. This is programmers laziness.
.. code:: ipython2 .. code:: python
reduce(C, (stack, uncons, uncons)) reduce(C, (stack, uncons, uncons))
@ -1887,7 +1887,7 @@ The display function should be changed too.
Clunky junk, but it will suffice for now. Clunky junk, but it will suffice for now.
.. code:: ipython2 .. code:: python
def doc_from_stack_effect(inputs, outputs): def doc_from_stack_effect(inputs, outputs):
switch = [False] # Do we need to display the '...' for the rest of the main stack? switch = [False] # Do we need to display the '...' for the rest of the main stack?
@ -1935,7 +1935,7 @@ Clunky junk, but it will suffice for now.
a.append(end) a.append(end)
return '[%s]' % ' '.join(a) return '[%s]' % ' '.join(a)
.. code:: ipython2 .. code:: python
for name, stack_effect_comment in sorted(NEW_DEFS.items()): for name, stack_effect_comment in sorted(NEW_DEFS.items()):
print name, '=', doc_from_stack_effect(*stack_effect_comment) print name, '=', doc_from_stack_effect(*stack_effect_comment)
@ -1973,7 +1973,7 @@ Clunky junk, but it will suffice for now.
uncons = ([a1 .1.] -- a1 [.1.]) uncons = ([a1 .1.] -- a1 [.1.])
.. code:: ipython2 .. code:: python
print ; print doc_from_stack_effect(*stack) print ; print doc_from_stack_effect(*stack)
print ; print doc_from_stack_effect(*C(stack, uncons)) print ; print doc_from_stack_effect(*C(stack, uncons))
@ -1993,7 +1993,7 @@ Clunky junk, but it will suffice for now.
(... a1 -- ... a1 [a1 ...]) (... a1 -- ... a1 [a1 ...])
.. code:: ipython2 .. code:: python
print doc_from_stack_effect(*C(ccons, stack)) print doc_from_stack_effect(*C(ccons, stack))
@ -2003,7 +2003,7 @@ Clunky junk, but it will suffice for now.
(... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...]) (... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])
.. code:: ipython2 .. code:: python
Q = C(ccons, stack) Q = C(ccons, stack)
@ -2024,7 +2024,7 @@ Clunky junk, but it will suffice for now.
This makes the ``compile_()`` function pretty simple as the stack effect This makes the ``compile_()`` function pretty simple as the stack effect
comments are now already in the form needed for the Python code: comments are now already in the form needed for the Python code:
.. code:: ipython2 .. code:: python
def compile_(name, f, doc=None): def compile_(name, f, doc=None):
i, o = f i, o = f
@ -2035,7 +2035,7 @@ comments are now already in the form needed for the Python code:
%s = stack %s = stack
return %s''' % (name, doc, i, o) return %s''' % (name, doc, i, o)
.. code:: ipython2 .. code:: python
print compile_('Q', Q) print compile_('Q', Q)
@ -2053,12 +2053,12 @@ comments are now already in the form needed for the Python code:
.. code:: ipython2 .. code:: python
unstack = (S[1], S[0]), S[1] unstack = (S[1], S[0]), S[1]
enstacken = S[0], (S[0], S[1]) enstacken = S[0], (S[0], S[1])
.. code:: ipython2 .. code:: python
print doc_from_stack_effect(*unstack) print doc_from_stack_effect(*unstack)
@ -2068,7 +2068,7 @@ comments are now already in the form needed for the Python code:
([.1.] --) ([.1.] --)
.. code:: ipython2 .. code:: python
print doc_from_stack_effect(*enstacken) print doc_from_stack_effect(*enstacken)
@ -2078,7 +2078,7 @@ comments are now already in the form needed for the Python code:
(-- [.0.]) (-- [.0.])
.. code:: ipython2 .. code:: python
print doc_from_stack_effect(*C(cons, unstack)) print doc_from_stack_effect(*C(cons, unstack))
@ -2088,7 +2088,7 @@ comments are now already in the form needed for the Python code:
(a1 [.1.] -- a1) (a1 [.1.] -- a1)
.. code:: ipython2 .. code:: python
print doc_from_stack_effect(*C(cons, enstacken)) print doc_from_stack_effect(*C(cons, enstacken))
@ -2098,7 +2098,7 @@ comments are now already in the form needed for the Python code:
(a1 [.1.] -- [[a1 .1.] .2.]) (a1 [.1.] -- [[a1 .1.] .2.])
.. code:: ipython2 .. code:: python
C(cons, unstack) C(cons, unstack)
@ -2117,7 +2117,7 @@ Part VI: Multiple Stack Effects
.. code:: ipython2 .. code:: python
class IntJoyType(NumberJoyType): prefix = 'i' class IntJoyType(NumberJoyType): prefix = 'i'
@ -2125,7 +2125,7 @@ Part VI: Multiple Stack Effects
F = map(FloatJoyType, _R) F = map(FloatJoyType, _R)
I = map(IntJoyType, _R) I = map(IntJoyType, _R)
.. code:: ipython2 .. code:: python
muls = [ muls = [
((I[2], (I[1], S[0])), (I[3], S[0])), ((I[2], (I[1], S[0])), (I[3], S[0])),
@ -2134,7 +2134,7 @@ Part VI: Multiple Stack Effects
((F[2], (F[1], S[0])), (F[3], S[0])), ((F[2], (F[1], S[0])), (F[3], S[0])),
] ]
.. code:: ipython2 .. code:: python
for f in muls: for f in muls:
print doc_from_stack_effect(*f) print doc_from_stack_effect(*f)
@ -2148,7 +2148,7 @@ Part VI: Multiple Stack Effects
(f1 f2 -- f3) (f1 f2 -- f3)
.. code:: ipython2 .. code:: python
for f in muls: for f in muls:
try: try:
@ -2164,7 +2164,7 @@ Part VI: Multiple Stack Effects
(a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2) (a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2)
.. code:: ipython2 .. code:: python
from itertools import product from itertools import product
@ -2180,7 +2180,7 @@ Part VI: Multiple Stack Effects
def MC(F, G): def MC(F, G):
return sorted(set(meta_compose(F, G))) return sorted(set(meta_compose(F, G)))
.. code:: ipython2 .. code:: python
for f in MC([dup], [mul]): for f in MC([dup], [mul]):
print doc_from_stack_effect(*f) print doc_from_stack_effect(*f)
@ -2191,7 +2191,7 @@ Part VI: Multiple Stack Effects
(n1 -- n2) (n1 -- n2)
.. code:: ipython2 .. code:: python
for f in MC([dup], muls): for f in MC([dup], muls):
print doc_from_stack_effect(*f) print doc_from_stack_effect(*f)
@ -2264,7 +2264,7 @@ Giving us two unifiers:
{c: a, d: b, .1.: .0.} {c: a, d: b, .1.: .0.}
{c: a, d: e, .1.: A* b .0.} {c: a, d: e, .1.: A* b .0.}
.. code:: ipython2 .. code:: python
class KleeneStar(object): class KleeneStar(object):
@ -2314,7 +2314,7 @@ Giving us two unifiers:
Can now return multiple results… Can now return multiple results…
.. code:: ipython2 .. code:: python
def unify(u, v, s=None): def unify(u, v, s=None):
if s is None: if s is None:
@ -2386,7 +2386,7 @@ Can now return multiple results…
def stacky(thing): def stacky(thing):
return thing.__class__ in {AnyJoyType, StackJoyType} return thing.__class__ in {AnyJoyType, StackJoyType}
.. code:: ipython2 .. code:: python
a = (As[1], S[1]) a = (As[1], S[1])
a a
@ -2400,7 +2400,7 @@ Can now return multiple results…
.. code:: ipython2 .. code:: python
b = (A[1], S[2]) b = (A[1], S[2])
b b
@ -2414,7 +2414,7 @@ Can now return multiple results…
.. code:: ipython2 .. code:: python
for result in unify(b, a): for result in unify(b, a):
print result, '->', update(result, a), update(result, b) print result, '->', update(result, a), update(result, b)
@ -2426,7 +2426,7 @@ Can now return multiple results…
{a1: a10001, s2: (a1*, s1)} -> (a1*, s1) (a10001, (a1*, s1)) {a1: a10001, s2: (a1*, s1)} -> (a1*, s1) (a10001, (a1*, s1))
.. code:: ipython2 .. code:: python
for result in unify(a, b): for result in unify(a, b):
print result, '->', update(result, a), update(result, b) print result, '->', update(result, a), update(result, b)
@ -2446,7 +2446,7 @@ Can now return multiple results…
(a1*, s1) [a1*] (a2, (a1*, s1)) [a2 a1*] (a1*, s1) [a1*] (a2, (a1*, s1)) [a2 a1*]
.. code:: ipython2 .. code:: python
sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0]) sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0])
@ -2458,7 +2458,7 @@ Can now return multiple results…
([n1* .1.] -- n0) ([n1* .1.] -- n0)
.. code:: ipython2 .. code:: python
f = (N[1], (N[2], (N[3], S[1]))), S[0] f = (N[1], (N[2], (N[3], S[1]))), S[0]
@ -2470,7 +2470,7 @@ Can now return multiple results…
(-- [n1 n2 n3 .1.]) (-- [n1 n2 n3 .1.])
.. code:: ipython2 .. code:: python
for result in unify(sum_[0], f): for result in unify(sum_[0], f):
print result, '->', update(result, sum_[1]) print result, '->', update(result, sum_[1])
@ -2489,7 +2489,7 @@ Can now return multiple results…
This function has to be modified to yield multiple results. This function has to be modified to yield multiple results.
.. code:: ipython2 .. code:: python
def compose(f, g): def compose(f, g):
(f_in, f_out), (g_in, g_out) = f, g (f_in, f_out), (g_in, g_out) = f, g
@ -2501,7 +2501,7 @@ This function has to be modified to yield multiple results.
.. code:: ipython2 .. code:: python
def meta_compose(F, G): def meta_compose(F, G):
for f, g in product(F, G): for f, g in product(F, G):
@ -2517,7 +2517,7 @@ This function has to be modified to yield multiple results.
for fg in compose(f, g): for fg in compose(f, g):
yield delabel(fg) yield delabel(fg)
.. code:: ipython2 .. code:: python
for f in MC([dup], muls): for f in MC([dup], muls):
print doc_from_stack_effect(*f) print doc_from_stack_effect(*f)
@ -2529,7 +2529,7 @@ This function has to be modified to yield multiple results.
(i1 -- i2) (i1 -- i2)
.. code:: ipython2 .. code:: python
@ -2542,7 +2542,7 @@ This function has to be modified to yield multiple results.
([n1* .1.] -- [n1* .1.] n1) ([n1* .1.] -- [n1* .1.] n1)
.. code:: ipython2 .. code:: python
@ -2556,7 +2556,7 @@ This function has to be modified to yield multiple results.
(n1 [n1* .1.] -- n2) (n1 [n1* .1.] -- n2)
.. code:: ipython2 .. code:: python
sum_ = (((N[1], (Ns[1], S[1])), S[0]), (N[0], S[0])) sum_ = (((N[1], (Ns[1], S[1])), S[0]), (N[0], S[0]))
print doc_from_stack_effect(*cons), print doc_from_stack_effect(*cons),
@ -2571,7 +2571,7 @@ This function has to be modified to yield multiple results.
(a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n1 [n1* .1.] -- n2) (a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n1 [n1* .1.] -- n2)
.. code:: ipython2 .. code:: python
a = (A[4], (As[1], (A[3], S[1]))) a = (A[4], (As[1], (A[3], S[1])))
a a
@ -2585,7 +2585,7 @@ This function has to be modified to yield multiple results.
.. code:: ipython2 .. code:: python
b = (A[1], (A[2], S[2])) b = (A[1], (A[2], S[2]))
b b
@ -2599,7 +2599,7 @@ This function has to be modified to yield multiple results.
.. code:: ipython2 .. code:: python
for result in unify(b, a): for result in unify(b, a):
print result print result
@ -2611,7 +2611,7 @@ This function has to be modified to yield multiple results.
{a1: a4, s2: (a1*, (a3, s1)), a2: a10003} {a1: a4, s2: (a1*, (a3, s1)), a2: a10003}
.. code:: ipython2 .. code:: python
for result in unify(a, b): for result in unify(a, b):
print result print result
@ -2681,7 +2681,7 @@ We need a type variable for Joy functions that can go in our expressions
and be used by the hybrid inferencer/interpreter. They have to store a and be used by the hybrid inferencer/interpreter. They have to store a
name and a list of stack effects. name and a list of stack effects.
.. code:: ipython2 .. code:: python
class FunctionJoyType(AnyJoyType): class FunctionJoyType(AnyJoyType):
@ -2703,14 +2703,14 @@ Specialized for Simple Functions and Combinators
For non-combinator functions the stack effects list contains stack For non-combinator functions the stack effects list contains stack
effect comments (represented by pairs of cons-lists as described above.) effect comments (represented by pairs of cons-lists as described above.)
.. code:: ipython2 .. code:: python
class SymbolJoyType(FunctionJoyType): class SymbolJoyType(FunctionJoyType):
prefix = 'F' prefix = 'F'
For combinators the list contains Python functions. For combinators the list contains Python functions.
.. code:: ipython2 .. code:: python
class CombinatorJoyType(FunctionJoyType): class CombinatorJoyType(FunctionJoyType):
@ -2731,7 +2731,7 @@ For combinators the list contains Python functions.
For simple combinators that have only one effect (like ``dip``) you only For simple combinators that have only one effect (like ``dip``) you only
need one function and it can be the combinator itself. need one function and it can be the combinator itself.
.. code:: ipython2 .. code:: python
import joy.library import joy.library
@ -2741,7 +2741,7 @@ For combinators that can have more than one effect (like ``branch``) you
have to write functions that each implement the action of one of the have to write functions that each implement the action of one of the
effects. effects.
.. code:: ipython2 .. code:: python
def branch_true(stack, expression, dictionary): def branch_true(stack, expression, dictionary):
(then, (else_, (flag, stack))) = stack (then, (else_, (flag, stack))) = stack
@ -2771,7 +2771,7 @@ updated along with the stack effects after doing unification or we risk
losing useful information. This was a straightforward, if awkward, losing useful information. This was a straightforward, if awkward,
modification to the call structure of ``meta_compose()`` et. al. modification to the call structure of ``meta_compose()`` et. al.
.. code:: ipython2 .. code:: python
ID = S[0], S[0] # Identity function. ID = S[0], S[0] # Identity function.
@ -2833,7 +2833,7 @@ cruft to convert the definitions in ``DEFS`` to the new
``SymbolJoyType`` objects, and some combinators. Here is an example of ``SymbolJoyType`` objects, and some combinators. Here is an example of
output from the current code : output from the current code :
.. code:: ipython2 .. code:: python
1/0 # (Don't try to run this cell! It's not going to work. This is "read only" code heh..) 1/0 # (Don't try to run this cell! It's not going to work. This is "read only" code heh..)
@ -2956,7 +2956,7 @@ module. But if youre interested in all that you should just use Prolog!
Anyhow, type *checking* is a few easy steps away. Anyhow, type *checking* is a few easy steps away.
.. code:: ipython2 .. code:: python
def _ge(self, other): def _ge(self, other):
return (issubclass(other.__class__, self.__class__) return (issubclass(other.__class__, self.__class__)

View File

@ -10,7 +10,7 @@ Huet <https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-
Given a datastructure on the stack we can navigate through it, modify Given a datastructure on the stack we can navigate through it, modify
it, and rebuild it using the “zipper” technique. it, and rebuild it using the “zipper” technique.
.. code:: ipython2 .. code:: python
from notebook_preamble import J, V, define from notebook_preamble import J, V, define
@ -23,7 +23,7 @@ strings, Symbols (strings that are names of functions) and sequences
`trees <https://en.wikipedia.org/wiki/Tree_%28data_structure%29>`__ out `trees <https://en.wikipedia.org/wiki/Tree_%28data_structure%29>`__ out
of sequences. of sequences.
.. code:: ipython2 .. code:: python
J('[1 [2 [3 4 25 6] 7] 8]') J('[1 [2 [3 4 25 6] 7] 8]')
@ -54,14 +54,14 @@ show the trace so you can see how it works. If we were going to use
these a lot it would make sense to write Python versions for efficiency, these a lot it would make sense to write Python versions for efficiency,
but see below. but see below.
.. code:: ipython2 .. code:: python
define('z-down == [] swap uncons swap') define('z-down == [] swap uncons swap')
define('z-up == swons swap shunt') define('z-up == swons swap shunt')
define('z-right == [swons] cons dip uncons swap') define('z-right == [swons] cons dip uncons swap')
define('z-left == swons [uncons swap] dip swap') define('z-left == swons [uncons swap] dip swap')
.. code:: ipython2 .. code:: python
V('[1 [2 [3 4 25 6] 7] 8] z-down') V('[1 [2 [3 4 25 6] 7] 8] z-down')
@ -77,7 +77,7 @@ but see below.
[] [[2 [3 4 25 6] 7] 8] 1 . [] [[2 [3 4 25 6] 7] 8] 1 .
.. code:: ipython2 .. code:: python
V('[] [[2 [3 4 25 6] 7] 8] 1 z-right') V('[] [[2 [3 4 25 6] 7] 8] 1 z-right')
@ -101,7 +101,7 @@ but see below.
[1] [8] [2 [3 4 25 6] 7] . [1] [8] [2 [3 4 25 6] 7] .
.. code:: ipython2 .. code:: python
J('[1] [8] [2 [3 4 25 6] 7] z-down') J('[1] [8] [2 [3 4 25 6] 7] z-down')
@ -111,7 +111,7 @@ but see below.
[1] [8] [] [[3 4 25 6] 7] 2 [1] [8] [] [[3 4 25 6] 7] 2
.. code:: ipython2 .. code:: python
J('[1] [8] [] [[3 4 25 6] 7] 2 z-right') J('[1] [8] [] [[3 4 25 6] 7] 2 z-right')
@ -121,7 +121,7 @@ but see below.
[1] [8] [2] [7] [3 4 25 6] [1] [8] [2] [7] [3 4 25 6]
.. code:: ipython2 .. code:: python
J('[1] [8] [2] [7] [3 4 25 6] z-down') J('[1] [8] [2] [7] [3 4 25 6] z-down')
@ -131,7 +131,7 @@ but see below.
[1] [8] [2] [7] [] [4 25 6] 3 [1] [8] [2] [7] [] [4 25 6] 3
.. code:: ipython2 .. code:: python
J('[1] [8] [2] [7] [] [4 25 6] 3 z-right') J('[1] [8] [2] [7] [] [4 25 6] 3 z-right')
@ -141,7 +141,7 @@ but see below.
[1] [8] [2] [7] [3] [25 6] 4 [1] [8] [2] [7] [3] [25 6] 4
.. code:: ipython2 .. code:: python
J('[1] [8] [2] [7] [3] [25 6] 4 z-right') J('[1] [8] [2] [7] [3] [25 6] 4 z-right')
@ -151,7 +151,7 @@ but see below.
[1] [8] [2] [7] [4 3] [6] 25 [1] [8] [2] [7] [4 3] [6] 25
.. code:: ipython2 .. code:: python
J('[1] [8] [2] [7] [4 3] [6] 25 sqr') J('[1] [8] [2] [7] [4 3] [6] 25 sqr')
@ -161,7 +161,7 @@ but see below.
[1] [8] [2] [7] [4 3] [6] 625 [1] [8] [2] [7] [4 3] [6] 625
.. code:: ipython2 .. code:: python
V('[1] [8] [2] [7] [4 3] [6] 625 z-up') V('[1] [8] [2] [7] [4 3] [6] 625 z-up')
@ -184,7 +184,7 @@ but see below.
[1] [8] [2] [7] [3 4 625 6] . [1] [8] [2] [7] [3 4 625 6] .
.. code:: ipython2 .. code:: python
J('[1] [8] [2] [7] [3 4 625 6] z-up') J('[1] [8] [2] [7] [3 4 625 6] z-up')
@ -194,7 +194,7 @@ but see below.
[1] [8] [2 [3 4 625 6] 7] [1] [8] [2 [3 4 625 6] 7]
.. code:: ipython2 .. code:: python
J('[1] [8] [2 [3 4 625 6] 7] z-up') J('[1] [8] [2 [3 4 625 6] 7] z-up')
@ -210,7 +210,7 @@ but see below.
In Joy we have the ``dip`` and ``infra`` combinators which can “target” In Joy we have the ``dip`` and ``infra`` combinators which can “target”
or “address” any particular item in a Joy tree structure. or “address” any particular item in a Joy tree structure.
.. code:: ipython2 .. code:: python
V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra') V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra')
@ -270,13 +270,13 @@ been embedded in a nested series of quoted programs, e.g.:
The ``Z`` function isnt hard to make. The ``Z`` function isnt hard to make.
.. code:: ipython2 .. code:: python
define('Z == [[] cons cons] step i') define('Z == [[] cons cons] step i')
Here it is in action in a simplified scenario. Here it is in action in a simplified scenario.
.. code:: ipython2 .. code:: python
V('1 [2 3 4] Z') V('1 [2 3 4] Z')
@ -314,7 +314,7 @@ Here it is in action in a simplified scenario.
And here it is doing the main thing. And here it is doing the main thing.
.. code:: ipython2 .. code:: python
J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z') J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z')