Convert syntax highlighter spec.
This commit is contained in:
parent
31c26cd235
commit
3f40e30c6f
|
|
@ -76,7 +76,7 @@ E.g.:
|
|||
Implementation
|
||||
--------------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from functools import partial as curry
|
||||
from itertools import product
|
||||
|
|
@ -86,7 +86,7 @@ Implementation
|
|||
|
||||
The empty set and the set of just the empty string.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
phi = 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
|
||||
look like ``0`` and ``1`` (zero and one) respectively.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
syms = O, l = frozenset({'0'}), frozenset({'1'})
|
||||
|
||||
|
|
@ -123,7 +123,7 @@ expression* is one of:
|
|||
|
||||
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.
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ only, these datastructures are immutable.
|
|||
String Representation of RE Datastructures
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def stringy(re):
|
||||
'''
|
||||
|
|
@ -175,11 +175,11 @@ Match anything. Often spelled “.”
|
|||
|
||||
I = (0|1)*
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
I = (KSTAR, (OR, O, l))
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print stringy(I)
|
||||
|
||||
|
|
@ -201,14 +201,14 @@ The example expression from Brzozowski:
|
|||
|
||||
Note that it contains one of everything.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
a = (CONS, I, (CONS, l, (CONS, l, (CONS, l, I))))
|
||||
b = (CONS, I, (CONS, O, l))
|
||||
c = (CONS, l, (KSTAR, l))
|
||||
it = (AND, a, (NOT, (OR, b, c)))
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print stringy(it)
|
||||
|
||||
|
|
@ -223,7 +223,7 @@ Note that it contains one of everything.
|
|||
|
||||
Let’s get that auxiliary predicate function ``δ`` out of the way.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
derivation.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def D(symbol):
|
||||
|
||||
|
|
@ -308,7 +308,7 @@ derivation.
|
|||
Compaction Rules
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def _compaction_rule(relation, one, zero, a, b):
|
||||
return (
|
||||
|
|
@ -320,7 +320,7 @@ Compaction Rules
|
|||
|
||||
An elegant symmetry.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
# R ∧ I = I ∧ 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
|
||||
are *pure* so this is fine.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
class Memo(object):
|
||||
|
||||
|
|
@ -365,7 +365,7 @@ With “Compaction”
|
|||
This version uses the rules above to perform compaction. It keeps the
|
||||
expressions from growing too large.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def D_compaction(symbol):
|
||||
|
||||
|
|
@ -414,7 +414,7 @@ Let’s try it out…
|
|||
|
||||
(FIXME: redo.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
o, z = D_compaction('0'), D_compaction('1')
|
||||
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 ``&``
|
||||
disappears once it has been matched.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from collections import defaultdict
|
||||
from pprint import pprint
|
||||
from string import ascii_lowercase
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
d0, d1 = D_compaction('0'), D_compaction('1')
|
||||
|
||||
``explore()``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def explore(re):
|
||||
|
||||
|
|
@ -645,7 +645,7 @@ disappears once it has been matched.
|
|||
|
||||
return table, accepting
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
table, accepting = explore(it)
|
||||
table
|
||||
|
|
@ -678,7 +678,7 @@ disappears once it has been matched.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
accepting
|
||||
|
||||
|
|
@ -697,7 +697,7 @@ Generate Diagram
|
|||
Once we have the FSM table and the set of accepting states we can
|
||||
generate the diagram above.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
_template = '''\
|
||||
digraph finite_state_machine {
|
||||
|
|
@ -722,7 +722,7 @@ generate the diagram above.
|
|||
)
|
||||
)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print make_graph(table, accepting)
|
||||
|
||||
|
|
@ -776,7 +776,7 @@ Trampoline Function
|
|||
Python has no GOTO statement but we can fake it with a “trampoline”
|
||||
function.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def trampoline(input_, jump_from, accepting):
|
||||
I = iter(input_)
|
||||
|
|
@ -793,7 +793,7 @@ Stream Functions
|
|||
Little helpers to process the iterator of our data (a “stream” of “1”
|
||||
and “0” characters, not bits.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
labels.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
a = lambda I: c if getch(I) else b
|
||||
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
|
||||
accepting state and ``g`` isn’t.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def acceptable(input_):
|
||||
return trampoline(input_, a, {h, i})
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for n in range(2**5):
|
||||
s = bin(n)[2:]
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
of 3 or 5 and ``False`` otherwise.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('P == [3 % not] dupdip 5 % not or')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('80 P')
|
||||
|
||||
|
|
@ -108,11 +108,11 @@ the counter to the running sum. This function will do that:
|
|||
|
||||
PE1.1 == + [+] dupdip
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE1.1 == + [+] dupdip')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('0 0 3 PE1.1')
|
||||
|
||||
|
|
@ -131,7 +131,7 @@ the counter to the running sum. This function will do that:
|
|||
3 3 .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
1000 / 15
|
||||
|
||||
|
|
@ -232,7 +232,7 @@ How many multiples to sum?
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
66 * 15
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ How many multiples to sum?
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
1000 - 990
|
||||
|
||||
|
|
@ -260,7 +260,7 @@ How many multiples to sum?
|
|||
|
||||
We only want the terms *less than* 1000.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
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')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('PE1')
|
||||
|
||||
|
|
@ -305,7 +305,7 @@ integer terms from the list.
|
|||
3 2 1 3 1 2 3
|
||||
0b 11 10 01 11 01 10 11 == 14811
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
0b11100111011011
|
||||
|
||||
|
|
@ -318,11 +318,11 @@ integer terms from the list.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE1.2 == [3 & PE1.1] dupdip 2 >>')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('0 0 14811 PE1.2')
|
||||
|
||||
|
|
@ -349,7 +349,7 @@ integer terms from the list.
|
|||
3 3 3702 .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('3 3 3702 PE1.2')
|
||||
|
||||
|
|
@ -376,7 +376,7 @@ integer terms from the list.
|
|||
8 5 925 .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('0 0 14811 7 [PE1.2] times pop')
|
||||
|
||||
|
|
@ -518,11 +518,11 @@ integer terms from the list.
|
|||
|
||||
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')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('PE1')
|
||||
|
||||
|
|
@ -542,17 +542,17 @@ Let's refactor
|
|||
14811 n [PE1.2] times pop
|
||||
n 14811 swap [PE1.2] times pop
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE1.3 == 14811 swap [PE1.2] times pop')
|
||||
|
||||
Now we can simplify the definition above:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
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]')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
terms to reach up to but not over one thousand.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('7 66 * 4 +')
|
||||
|
||||
|
|
@ -611,7 +611,7 @@ terms to reach up to but not over one thousand.
|
|||
Here they are...
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('PE1.terms 466 [x] times pop')
|
||||
|
||||
|
|
@ -624,7 +624,7 @@ Here they are...
|
|||
...and they do sum to 999.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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,
|
||||
leaving just the sum.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
ten.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
you want to work it out or you can take my word for it.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('F == dup ++ * 2 floordiv')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('10 F')
|
||||
|
||||
|
|
@ -727,7 +727,7 @@ And ending with:
|
|||
|
||||
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')
|
||||
|
||||
|
|
@ -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]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
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')
|
||||
|
||||
|
|
@ -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:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('6945 33 * [993 995 996 999] cons sum')
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ Using ``x`` to Generate Values
|
|||
|
||||
Cf. jp-reprod.html
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
|||
|
||||
Let’s try it:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('[0 swap [dup ++] dip rest cons] x')
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ Let’s try it:
|
|||
After one application of ``x`` the quoted program contains ``1`` and
|
||||
``0`` is below it on the stack.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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``
|
||||
----------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('direco == dip rest cons')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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] swoncat cons
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('G == [direco] cons [swap] swoncat cons')
|
||||
|
||||
Let’s try it out:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('0 [dup ++] G')
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ Let’s try it out:
|
|||
[0 swap [dup ++] direco]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('0 [dup ++] G x x x pop')
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ Let’s try it out:
|
|||
Powers of 2
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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``
|
||||
with the ``x`` combinator.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
int right two bits.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE1.1 == dup [3 &] dip 2 >>')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('14811 PE1.1')
|
||||
|
||||
|
|
@ -252,7 +252,7 @@ int right two bits.
|
|||
|
||||
If we plug ``14811`` and ``[PE1.1]`` into our generator form…
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
if so.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE1.1.check == dup [pop 14811] [] branch')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('14811 [PE1.1.check PE1.1] G')
|
||||
|
||||
|
|
@ -294,7 +294,7 @@ if so.
|
|||
[14811 swap [PE1.1.check PE1.1] direco]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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. It’s worked out that we need to use all seven
|
||||
numbers sixty-six times and then four more.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
-------------------------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE1.2 == + dup [+] dip')
|
||||
|
||||
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')
|
||||
|
||||
|
|
@ -445,15 +445,15 @@ Putting it all together:
|
|||
F == + [popdd over] cons infra uncons
|
||||
fib_gen == [1 1 F]
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('fib == + [popdd over] cons infra uncons')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('fib_gen == [1 1 fib]')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
``pop``\ s it otherwise.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE2.1 == dup 2 % [+] [pop] branch')
|
||||
|
||||
And a predicate function that detects when the terms in the series
|
||||
“exceed four million”.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('>4M == 4000000 >')
|
||||
|
||||
|
|
@ -488,11 +488,11 @@ Now it’s straightforward to define ``PE2`` as a recursive function that
|
|||
generates terms in the Fibonacci sequence until they exceed four million
|
||||
and sums the even ones.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('PE2')
|
||||
|
||||
|
|
@ -535,7 +535,7 @@ So the Fibonacci sequence considered in terms of just parity would be:
|
|||
|
||||
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.
|
||||
|
||||
|
|
@ -547,7 +547,7 @@ Every third term is even.
|
|||
|
||||
Drive the generator three times and ``popop`` the two odd terms.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('PE2.2 == x x x [popop] dipd')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
``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')
|
||||
|
||||
|
|
@ -593,11 +593,11 @@ modifications to the default ``x``?
|
|||
An Interesting Variation
|
||||
------------------------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('codireco == cons dip rest cons')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('[0 [dup ++] codireco] x')
|
||||
|
||||
|
|
@ -620,11 +620,11 @@ An Interesting Variation
|
|||
0 [1 [dup ++] codireco] .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('G == [codireco] cons cons')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('230 [dup ++] G 5 [x] times pop')
|
||||
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ TBD (look in the :module: joy.parser module.)
|
|||
Examples
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
joy.parser.text_to_expression('1 2 3 4 5') # A simple sequence.
|
||||
|
||||
|
|
@ -160,7 +160,7 @@ Examples
|
|||
(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
|
||||
|
||||
|
|
@ -170,7 +170,7 @@ Examples
|
|||
((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
|
||||
# a Symbol, no lookup at
|
||||
|
|
@ -184,7 +184,7 @@ Examples
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -221,7 +221,7 @@ provide control-flow and higher-order operations.
|
|||
|
||||
Many of the functions are defined in Python, like ``dip``:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
continuation) and returns control to the interpreter.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print joy.library.definitions
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
functions on otherwise undistinguished Joy datastructures.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from notebook_preamble import D, J, V, define, DefinitionWrapper
|
||||
|
||||
|
|
@ -87,11 +87,11 @@ Definition:
|
|||
|
||||
Tree-new == swap [[] []] cons cons
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('Tree-new == swap [[] []] cons cons')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('"v" "k" Tree-new')
|
||||
|
||||
|
|
@ -163,11 +163,11 @@ comparison operator:
|
|||
P < == pop roll> pop first <
|
||||
P == pop roll> pop first
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('P == pop roll> pop first')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('["old_key" 23 [] []] 17 "new_key" ["..."] P')
|
||||
|
||||
|
|
@ -242,11 +242,11 @@ And so ``T`` is just:
|
|||
|
||||
T == cons cons [dipdd] cons infra
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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')
|
||||
|
||||
|
|
@ -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] [P <] [Te] [Ee] ifte
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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')
|
||||
|
||||
|
|
@ -320,11 +320,11 @@ Example:
|
|||
key new_value [ left right] cons cons
|
||||
[key new_value left right]
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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')
|
||||
|
||||
|
|
@ -355,14 +355,14 @@ Putting it all together:
|
|||
|
||||
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')
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[] 23 "b" Tree-add') # Initial
|
||||
|
||||
|
|
@ -372,7 +372,7 @@ Examples
|
|||
['b' 23 [] []]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('["b" 23 [] []] 88 "c" Tree-add') # Greater than
|
||||
|
||||
|
|
@ -382,7 +382,7 @@ Examples
|
|||
['b' 23 [] ['c' 88 [] []]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('["b" 23 [] []] 88 "a" Tree-add') # Less than
|
||||
|
||||
|
|
@ -392,7 +392,7 @@ Examples
|
|||
['b' 23 ['a' 88 [] []] []]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('["b" 23 [] []] 88 "b" Tree-add') # Equal to
|
||||
|
||||
|
|
@ -402,7 +402,7 @@ Examples
|
|||
['b' 88 [] []]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 [] []]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step')
|
||||
|
||||
|
|
@ -444,7 +444,7 @@ values:
|
|||
------------------------- a < b
|
||||
L
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J("1 0 ['G'] ['E'] ['L'] cmp")
|
||||
|
||||
|
|
@ -454,7 +454,7 @@ values:
|
|||
'G'
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J("1 1 ['G'] ['E'] ['L'] cmp")
|
||||
|
||||
|
|
@ -464,7 +464,7 @@ values:
|
|||
'E'
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J("0 1 ['G'] ['E'] ['L'] cmp")
|
||||
|
||||
|
|
@ -514,7 +514,7 @@ Or just:
|
|||
|
||||
P == over [popop popop first] nullary
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -685,14 +685,14 @@ Working backward:
|
|||
|
||||
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')
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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")
|
||||
|
||||
|
|
@ -712,7 +712,7 @@ Examples
|
|||
'b' 'a' 'c'
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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>`__
|
||||
time.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 [] []]] []]] []]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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')
|
||||
|
||||
|
|
@ -758,11 +758,11 @@ time.
|
|||
And with that we can write a little program ``unique`` to remove
|
||||
duplicate items from a list.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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.
|
||||
|
||||
|
|
@ -872,7 +872,7 @@ Let’s do a little semantic factoring:
|
|||
|
||||
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')
|
||||
|
||||
|
|
@ -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')
|
||||
|
||||
|
|
@ -1070,7 +1070,7 @@ So:
|
|||
|
||||
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.
|
||||
# The original Joy system has "hide" which is a meta-command which allows you to use named
|
||||
|
|
@ -1088,7 +1088,7 @@ So:
|
|||
] genrec
|
||||
''')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get')
|
||||
|
||||
|
|
@ -1098,7 +1098,7 @@ So:
|
|||
'mike not in tree'
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('["gary" 23 [] []] "gary" [popop "err"] Tree-get')
|
||||
|
||||
|
|
@ -1108,7 +1108,7 @@ So:
|
|||
23
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('''
|
||||
|
||||
|
|
@ -1124,7 +1124,7 @@ So:
|
|||
2
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('''
|
||||
|
||||
|
|
@ -1500,7 +1500,7 @@ Refactoring
|
|||
By the standards of the code I’ve written so far, this is a *huge* Joy
|
||||
program.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
DefinitionWrapper.add_definitions('''
|
||||
first_two == uncons uncons pop
|
||||
|
|
@ -1519,7 +1519,7 @@ program.
|
|||
Tree-Delete == [pop not] [pop] [R0] [R1] genrec
|
||||
''', D)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ")
|
||||
|
||||
|
|
@ -1529,7 +1529,7 @@ program.
|
|||
['a' 23 [] ['b' 88 [] []]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ")
|
||||
|
||||
|
|
@ -1539,7 +1539,7 @@ program.
|
|||
['a' 23 [] ['c' 44 [] []]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ")
|
||||
|
||||
|
|
@ -1549,7 +1549,7 @@ program.
|
|||
['b' 88 [] ['c' 44 [] []]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ")
|
||||
|
||||
|
|
@ -1559,7 +1559,7 @@ program.
|
|||
['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 [] []]]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 [] []]]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 right and say it’s the definition of the ``quadratic`` function:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
|
||||
|
||||
Let’s try it out:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
get the results. This is pretty typical of Joy code.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('-5 1 4 quadratic')
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
code.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def hylomorphism(c, F, P, G):
|
||||
'''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
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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]``
|
||||
- ``[F]`` is ``[+]``
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
|
||||
|
||||
Let’s try it:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('5 triangular_number')
|
||||
|
||||
|
|
@ -219,7 +219,7 @@ Let’s try it:
|
|||
10
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
== [0 <=] [pop []] [-- dup] [dip swons] genrec
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
== [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
== [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
== [] swap [0 <=] [pop] [[swons] dupdip --] primrec
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('5 ranger_reverse')
|
||||
|
||||
|
|
@ -501,7 +501,7 @@ and makes some new value.
|
|||
|
||||
C == [not] c [uncons swap] [F] hylomorphism
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('swuncons == uncons swap') # Awkward name.
|
||||
|
||||
|
|
@ -511,11 +511,11 @@ An example of a catamorphism is the sum function.
|
|||
|
||||
sum == [not] 0 [swuncons] [+] hylomorphism
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('sum == [not] 0 [swuncons] [+] hylomorphism')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[5 4 3 2 1] sum')
|
||||
|
||||
|
|
@ -531,7 +531,7 @@ The ``step`` combinator
|
|||
The ``step`` combinator will usually be better to use than
|
||||
``catamorphism``.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[5 4 3 2 1] sum')
|
||||
|
||||
|
|
@ -592,11 +592,11 @@ With:
|
|||
G == --
|
||||
P == 1 <=
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('5 factorial')
|
||||
|
||||
|
|
@ -635,11 +635,11 @@ We would use:
|
|||
G == rest dup
|
||||
P == not
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[1 2 3] tails')
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ dictionary. However, there’s no function that does that. Adding a new
|
|||
function to the dictionary is a meta-interpreter action, you have to do
|
||||
it in Python, not Joy.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from notebook_preamble import D, J, V
|
||||
|
||||
A long trace
|
||||
------------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
up evaluation and make the trace more readable.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from joy.library import SimpleFunctionWrapper
|
||||
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,
|
||||
and re-evaluate the expression.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
D['size'] = size
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ A shorter trace
|
|||
|
||||
You can see that ``size`` now executes in a single step.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
V('[23 18] average')
|
||||
|
||||
|
|
|
|||
|
|
@ -148,11 +148,11 @@ Working backwards:
|
|||
Define ``treestep``
|
||||
-------------------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from notebook_preamble import D, J, V, define, DefinitionWrapper
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
DefinitionWrapper.add_definitions('''
|
||||
|
||||
|
|
@ -173,7 +173,7 @@ all nodes in a tree with this function:
|
|||
|
||||
sumtree == [pop 0] [] [sum +] treestep
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('sumtree == [pop 0] [] [sum +] treestep')
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ Running this function on an empty tree value gives zero:
|
|||
------------------------------------
|
||||
0
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[] sumtree') # Empty tree.
|
||||
|
||||
|
|
@ -205,7 +205,7 @@ Running it on a non-empty node:
|
|||
n m +
|
||||
n+m
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[23] sumtree') # No child trees.
|
||||
|
||||
|
|
@ -215,7 +215,7 @@ Running it on a non-empty node:
|
|||
23
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[23 []] sumtree') # Child tree, empty.
|
||||
|
||||
|
|
@ -225,7 +225,7 @@ Running it on a non-empty node:
|
|||
23
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees.
|
||||
|
||||
|
|
@ -235,7 +235,7 @@ Running it on a non-empty node:
|
|||
32
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc...
|
||||
|
||||
|
|
@ -245,7 +245,7 @@ Running it on a non-empty node:
|
|||
49
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 []]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 []]]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree')
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ Running it on a non-empty node:
|
|||
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.
|
||||
|
||||
|
|
@ -295,7 +295,7 @@ Running it on a non-empty node:
|
|||
6
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function.
|
||||
|
||||
|
|
@ -339,7 +339,7 @@ Traversal
|
|||
|
||||
This doesn’t 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')
|
||||
|
||||
|
|
@ -369,7 +369,7 @@ So:
|
|||
|
||||
[] [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')
|
||||
|
||||
|
|
@ -401,7 +401,7 @@ So:
|
|||
|
||||
[] [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')
|
||||
|
||||
|
|
@ -429,7 +429,7 @@ Plugging in our BTree structure:
|
|||
|
||||
[key value] N [left right] [K] C
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
|
||||
|
||||
|
|
@ -444,7 +444,7 @@ Plugging in our BTree structure:
|
|||
|
||||
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')
|
||||
|
||||
|
|
@ -456,7 +456,7 @@ Iteration through the nodes
|
|||
|
||||
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')
|
||||
|
||||
|
|
@ -468,7 +468,7 @@ Sum the nodes’ keys.
|
|||
|
||||
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')
|
||||
|
||||
|
|
@ -574,7 +574,7 @@ Putting it together
|
|||
|
||||
To me, that seems simpler than the ``genrec`` version.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
DefinitionWrapper.add_definitions('''
|
||||
|
||||
|
|
@ -587,7 +587,7 @@ To me, that seems simpler than the ``genrec`` version.
|
|||
|
||||
''', D)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('''\
|
||||
|
||||
|
|
@ -603,7 +603,7 @@ To me, that seems simpler than the ``genrec`` version.
|
|||
15
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('''\
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
Type Checking
|
||||
=============
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
import logging, sys
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ Type Checking
|
|||
level=logging.INFO,
|
||||
)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from joy.utils.types import (
|
||||
doc_from_stack_effect,
|
||||
|
|
@ -22,7 +22,7 @@ Type Checking
|
|||
JoyTypeError,
|
||||
)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
D = FUNCTIONS.copy()
|
||||
del D['product']
|
||||
|
|
@ -31,7 +31,7 @@ Type Checking
|
|||
An Example
|
||||
----------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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]) ∘
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print doc_from_stack_effect(fi, fo)
|
||||
|
||||
|
|
@ -56,13 +56,13 @@ An Example
|
|||
([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from joy.parser import text_to_expression
|
||||
from joy.utils.stack import stack_to_string
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
e = text_to_expression('0 1 2 [3 4]') # reverse order
|
||||
print stack_to_string(e)
|
||||
|
|
@ -73,7 +73,7 @@ An Example
|
|||
[3 4] 2 1 0
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
u = unify(e, fi)[0]
|
||||
u
|
||||
|
|
@ -87,7 +87,7 @@ An Example
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
g = reify(u, (fi, fo))
|
||||
print doc_from_stack_effect(*g)
|
||||
|
|
@ -101,11 +101,11 @@ An Example
|
|||
Unification Works “in Reverse”
|
||||
------------------------------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
e = text_to_expression('[2 3]')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
u = unify(e, fo)[0] # output side, not input side
|
||||
u
|
||||
|
|
@ -119,7 +119,7 @@ Unification Works “in Reverse”
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
g = reify(u, (fi, fo))
|
||||
print doc_from_stack_effect(*g)
|
||||
|
|
@ -133,7 +133,7 @@ Unification Works “in Reverse”
|
|||
Failing a Check
|
||||
---------------
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
fi, fo = infer(dup, mul)[0]
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ Failing a Check
|
|||
31 (i1 -- i2) ∘
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
e = text_to_expression('"two"')
|
||||
print stack_to_string(e)
|
||||
|
|
@ -157,7 +157,7 @@ Failing a Check
|
|||
'two'
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
try:
|
||||
unify(e, fi)
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ Compiling ``pop∘swap∘roll<``
|
|||
|
||||
The simplest way to “compile” this function would be something like:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def poswrd(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:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def poswrd(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
|
||||
following Python code:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def F(stack):
|
||||
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
|
||||
|
|
@ -408,7 +408,7 @@ Representing Stack Effect Comments in Python
|
|||
I’m going to use pairs of tuples of type descriptors, which will be
|
||||
integers or tuples of type descriptors:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
roll_dn = (1, 2, 3), (2, 3, 1)
|
||||
|
||||
|
|
@ -419,7 +419,7 @@ integers or tuples of type descriptors:
|
|||
``compose()``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def compose(f, g):
|
||||
|
||||
|
|
@ -465,7 +465,7 @@ integers or tuples of type descriptors:
|
|||
``unify()``
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def unify(u, v, s=None):
|
||||
if s is None:
|
||||
|
|
@ -483,7 +483,7 @@ integers or tuples of type descriptors:
|
|||
``update()``
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def update(s, term):
|
||||
if not isinstance(term, tuple):
|
||||
|
|
@ -493,7 +493,7 @@ integers or tuples of type descriptors:
|
|||
``relabel()``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def relabel(left, right):
|
||||
return left, _1000(right)
|
||||
|
|
@ -517,7 +517,7 @@ integers or tuples of type descriptors:
|
|||
``delabel()``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def delabel(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
|
||||
exception if they can’t be composed due to type conflicts.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def C(f, g):
|
||||
f, g = relabel(f, g)
|
||||
|
|
@ -560,7 +560,7 @@ exception if they can’t be composed due to type conflicts.)
|
|||
|
||||
Let’s try it out.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(pop, swap)
|
||||
|
||||
|
|
@ -573,7 +573,7 @@ Let’s try it out.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(C(pop, swap), roll_dn)
|
||||
|
||||
|
|
@ -586,7 +586,7 @@ Let’s try it out.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(swap, roll_dn)
|
||||
|
||||
|
|
@ -599,7 +599,7 @@ Let’s try it out.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(pop, C(swap, roll_dn))
|
||||
|
||||
|
|
@ -612,7 +612,7 @@ Let’s try it out.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
poswrd = reduce(C, (pop, swap, roll_dn))
|
||||
poswrd
|
||||
|
|
@ -633,13 +633,13 @@ Here’s that trick to represent functions like ``rest`` and ``cons`` that
|
|||
manipulate stacks. We use a cons-list of tuples and give the tails their
|
||||
own numbers. Then everything above already works.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
rest = ((1, 2),), (2,)
|
||||
|
||||
cons = (1, 2), ((1, 2),)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(poswrd, rest)
|
||||
|
||||
|
|
@ -671,7 +671,7 @@ The translation table, if you will, would be:
|
|||
0: 0,
|
||||
}
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 won’t
|
||||
work:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
uncons = ((1, 2),), (1, 2)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
try:
|
||||
C(cons, uncons)
|
||||
|
|
@ -723,7 +723,7 @@ The problem is that the ``unify()`` function as written doesn’t handle
|
|||
the case when both terms are tuples. We just have to add a clause to
|
||||
deal with this recursively:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def unify(u, v, s=None):
|
||||
if s is None:
|
||||
|
|
@ -753,7 +753,7 @@ deal with this recursively:
|
|||
|
||||
return s
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(cons, uncons)
|
||||
|
||||
|
|
@ -771,7 +771,7 @@ Part III: Compiling Yin Functions
|
|||
|
||||
Now consider the Python function we would like to derive:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def F_python(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:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
F[0]
|
||||
|
||||
|
|
@ -816,7 +816,7 @@ Eh?
|
|||
|
||||
And the return tuple
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
F[1]
|
||||
|
||||
|
|
@ -848,7 +848,7 @@ Python Identifiers
|
|||
We want to substitute Python identifiers for the integers. I’m going to
|
||||
repurpose ``joy.parser.Symbol`` class for this:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from collections import defaultdict
|
||||
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
|
||||
you should skip it for now and read it later if you’re interested.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def doc_from_stack_effect(inputs, outputs):
|
||||
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()``
|
||||
function.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def compile_(name, f, doc=None):
|
||||
if doc is None:
|
||||
|
|
@ -932,7 +932,7 @@ function.)
|
|||
|
||||
Here it is in action:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
source = compile_('F', F)
|
||||
|
||||
|
|
@ -949,7 +949,7 @@ Here it is in action:
|
|||
|
||||
Compare:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def F_python(stack):
|
||||
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
|
||||
|
|
@ -957,7 +957,7 @@ Compare:
|
|||
|
||||
Next steps:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
L = {}
|
||||
|
||||
|
|
@ -976,16 +976,16 @@ Next steps:
|
|||
|
||||
Let’s try it out:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from notebook_preamble import D, J, V
|
||||
from joy.library import SimpleFunctionWrapper
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
D['F'] = SimpleFunctionWrapper(L['F'])
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
from their stack effect comments:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def defs():
|
||||
|
||||
|
|
@ -1036,7 +1036,7 @@ from their stack effect comments:
|
|||
|
||||
return locals()
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for name, stack_effect_comment in sorted(defs().items()):
|
||||
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
|
||||
make it fairly easy to reuse most of the code above.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
class AnyJoyType(object):
|
||||
|
||||
|
|
@ -1251,14 +1251,14 @@ make it fairly easy to reuse most of the code above.
|
|||
|
||||
Mess with it a little:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from itertools import permutations
|
||||
|
||||
“Any” types can be specialized to numbers and stacks, but not vice
|
||||
versa:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for a, b in permutations((A[0], N[0], S[0]), 2):
|
||||
print a, '>=', b, '->', a >= b
|
||||
|
|
@ -1278,7 +1278,7 @@ Our crude `Numerical
|
|||
Tower <https://en.wikipedia.org/wiki/Numerical_tower>`__ of *numbers* >
|
||||
*floats* > *integers* works as well (but we’re not going to use it yet):
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
|
||||
print a, '>=', b, '->', a >= b
|
||||
|
|
@ -1303,13 +1303,13 @@ Tower <https://en.wikipedia.org/wiki/Numerical_tower>`__ of *numbers* >
|
|||
Typing ``sqr``
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
dup = (A[1],), (A[1], A[1])
|
||||
|
||||
mul = (N[1], N[2]), (N[3],)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
dup
|
||||
|
||||
|
|
@ -1322,7 +1322,7 @@ Typing ``sqr``
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
mul
|
||||
|
||||
|
|
@ -1340,7 +1340,7 @@ Modifying the Inferencer
|
|||
|
||||
Re-labeling still works fine:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
of how many labels of each domain it has “seen”.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
delabel(foo)
|
||||
|
||||
|
|
@ -1399,7 +1399,7 @@ of how many labels of each domain it has “seen”.
|
|||
``unify()`` version 3
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def unify(u, v, s=None):
|
||||
if s is None:
|
||||
|
|
@ -1449,7 +1449,7 @@ of how many labels of each domain it has “seen”.
|
|||
|
||||
Rewrite the stack effect comments:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def defs():
|
||||
|
||||
|
|
@ -1503,11 +1503,11 @@ Rewrite the stack effect comments:
|
|||
|
||||
return locals()
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
DEFS = defs()
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for name, stack_effect_comment in sorted(DEFS.items()):
|
||||
print name, '=', doc_from_stack_effect(*stack_effect_comment)
|
||||
|
|
@ -1543,14 +1543,14 @@ Rewrite the stack effect comments:
|
|||
uncons = ([a1 .1.] -- a1 [.1.])
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
globals().update(DEFS)
|
||||
|
||||
Compose ``dup`` and ``mul``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(dup, mul)
|
||||
|
||||
|
|
@ -1565,7 +1565,7 @@ Compose ``dup`` and ``mul``
|
|||
|
||||
Revisit the ``F`` function, works fine.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
|
||||
F
|
||||
|
|
@ -1579,7 +1579,7 @@ Revisit the ``F`` function, works fine.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
also get the effect of combinators in some limited cases.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def neato(*funcs):
|
||||
print doc_from_stack_effect(*reduce(C, funcs))
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
# e.g. [swap] dip
|
||||
neato(rollup, swap, rolldown)
|
||||
|
|
@ -1608,7 +1608,7 @@ also get the effect of combinators in some limited cases.
|
|||
(a1 a2 a3 -- a2 a1 a3)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
# e.g. [popop] dipd
|
||||
neato(popdd, rolldown, pop)
|
||||
|
|
@ -1619,7 +1619,7 @@ also get the effect of combinators in some limited cases.
|
|||
(a1 a2 a3 a4 -- a3 a4)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
# Reverse the order of the top three items.
|
||||
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
|
||||
the ``compile_()`` function doesn’t need to generate them anymore:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def compile_(name, f, doc=None):
|
||||
inputs, outputs = f
|
||||
|
|
@ -1652,7 +1652,7 @@ the ``compile_()`` function doesn’t need to generate them anymore:
|
|||
%s = stack
|
||||
return %s''' % (name, doc, i, o)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print compile_('F', F)
|
||||
|
||||
|
|
@ -1668,7 +1668,7 @@ the ``compile_()`` function doesn’t need to generate them anymore:
|
|||
But it cannot magically create new functions that involve e.g. math and
|
||||
such. Note that this is *not* a ``sqr`` function implementation:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
comments. We can write a function to check that:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from itertools import imap
|
||||
|
||||
|
|
@ -1704,7 +1704,7 @@ comments. We can write a function to check that:
|
|||
def compilable(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()):
|
||||
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
|
||||
tuples.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def compose(f, g):
|
||||
(f_in, f_out), (g_in, g_out) = f, g
|
||||
|
|
@ -1840,7 +1840,7 @@ tuples.)
|
|||
I don’t want to rewrite all the defs myself, so I’ll write a little
|
||||
conversion function instead. This is programmer’s laziness.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def sequence_to_stack(seq, stack=StackJoyType(23)):
|
||||
for item in seq: stack = item, stack
|
||||
|
|
@ -1854,7 +1854,7 @@ conversion function instead. This is programmer’s laziness.
|
|||
NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1])
|
||||
globals().update(NEW_DEFS)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(stack, uncons)
|
||||
|
||||
|
|
@ -1867,7 +1867,7 @@ conversion function instead. This is programmer’s laziness.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
reduce(C, (stack, uncons, uncons))
|
||||
|
||||
|
|
@ -1887,7 +1887,7 @@ The display function should be changed too.
|
|||
|
||||
Clunky junk, but it will suffice for now.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def doc_from_stack_effect(inputs, outputs):
|
||||
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)
|
||||
return '[%s]' % ' '.join(a)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for name, stack_effect_comment in sorted(NEW_DEFS.items()):
|
||||
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.])
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print ; print doc_from_stack_effect(*stack)
|
||||
print ; print doc_from_stack_effect(*C(stack, uncons))
|
||||
|
|
@ -1993,7 +1993,7 @@ Clunky junk, but it will suffice for now.
|
|||
(... a1 -- ... a1 [a1 ...])
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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.] ...])
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
comments are now already in the form needed for the Python code:
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def compile_(name, f, doc=None):
|
||||
i, o = f
|
||||
|
|
@ -2035,7 +2035,7 @@ comments are now already in the form needed for the Python code:
|
|||
%s = stack
|
||||
return %s''' % (name, doc, i, o)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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]
|
||||
enstacken = S[0], (S[0], S[1])
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print doc_from_stack_effect(*unstack)
|
||||
|
||||
|
|
@ -2068,7 +2068,7 @@ comments are now already in the form needed for the Python code:
|
|||
([.1.] --)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
print doc_from_stack_effect(*enstacken)
|
||||
|
||||
|
|
@ -2078,7 +2078,7 @@ comments are now already in the form needed for the Python code:
|
|||
(-- [.0.])
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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.])
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
C(cons, unstack)
|
||||
|
||||
|
|
@ -2117,7 +2117,7 @@ Part VI: Multiple Stack Effects
|
|||
|
||||
…
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
class IntJoyType(NumberJoyType): prefix = 'i'
|
||||
|
||||
|
|
@ -2125,7 +2125,7 @@ Part VI: Multiple Stack Effects
|
|||
F = map(FloatJoyType, _R)
|
||||
I = map(IntJoyType, _R)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
muls = [
|
||||
((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])),
|
||||
]
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for f in muls:
|
||||
print doc_from_stack_effect(*f)
|
||||
|
|
@ -2148,7 +2148,7 @@ Part VI: Multiple Stack Effects
|
|||
(f1 f2 -- f3)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for f in muls:
|
||||
try:
|
||||
|
|
@ -2164,7 +2164,7 @@ Part VI: Multiple Stack Effects
|
|||
(a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
from itertools import product
|
||||
|
||||
|
|
@ -2180,7 +2180,7 @@ Part VI: Multiple Stack Effects
|
|||
def MC(F, G):
|
||||
return sorted(set(meta_compose(F, G)))
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for f in MC([dup], [mul]):
|
||||
print doc_from_stack_effect(*f)
|
||||
|
|
@ -2191,7 +2191,7 @@ Part VI: Multiple Stack Effects
|
|||
(n1 -- n2)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for f in MC([dup], muls):
|
||||
print doc_from_stack_effect(*f)
|
||||
|
|
@ -2264,7 +2264,7 @@ Giving us two unifiers:
|
|||
{c: a, d: b, .1.: .0.}
|
||||
{c: a, d: e, .1.: A* b .0.}
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
class KleeneStar(object):
|
||||
|
||||
|
|
@ -2314,7 +2314,7 @@ Giving us two unifiers:
|
|||
|
||||
Can now return multiple results…
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def unify(u, v, s=None):
|
||||
if s is None:
|
||||
|
|
@ -2386,7 +2386,7 @@ Can now return multiple results…
|
|||
def stacky(thing):
|
||||
return thing.__class__ in {AnyJoyType, StackJoyType}
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
a = (As[1], S[1])
|
||||
a
|
||||
|
|
@ -2400,7 +2400,7 @@ Can now return multiple results…
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
b = (A[1], S[2])
|
||||
b
|
||||
|
|
@ -2414,7 +2414,7 @@ Can now return multiple results…
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for result in unify(b, a):
|
||||
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))
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for result in unify(a, 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*]
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0])
|
||||
|
||||
|
|
@ -2458,7 +2458,7 @@ Can now return multiple results…
|
|||
([n1* .1.] -- n0)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
f = (N[1], (N[2], (N[3], S[1]))), S[0]
|
||||
|
||||
|
|
@ -2470,7 +2470,7 @@ Can now return multiple results…
|
|||
(-- [n1 n2 n3 .1.])
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for result in unify(sum_[0], f):
|
||||
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.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def compose(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):
|
||||
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):
|
||||
yield delabel(fg)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for f in MC([dup], muls):
|
||||
print doc_from_stack_effect(*f)
|
||||
|
|
@ -2529,7 +2529,7 @@ This function has to be modified to yield multiple results.
|
|||
(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)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
|
||||
|
||||
|
|
@ -2556,7 +2556,7 @@ This function has to be modified to yield multiple results.
|
|||
(n1 [n1* .1.] -- n2)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
sum_ = (((N[1], (Ns[1], S[1])), S[0]), (N[0], S[0]))
|
||||
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)
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
a = (A[4], (As[1], (A[3], S[1])))
|
||||
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
|
||||
|
|
@ -2599,7 +2599,7 @@ This function has to be modified to yield multiple results.
|
|||
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for result in unify(b, a):
|
||||
print result
|
||||
|
|
@ -2611,7 +2611,7 @@ This function has to be modified to yield multiple results.
|
|||
{a1: a4, s2: (a1*, (a3, s1)), a2: a10003}
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
for result in unify(a, b):
|
||||
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
|
||||
name and a list of stack effects.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
class FunctionJoyType(AnyJoyType):
|
||||
|
||||
|
|
@ -2703,14 +2703,14 @@ Specialized for Simple Functions and Combinators
|
|||
For non-combinator functions the stack effects list contains stack
|
||||
effect comments (represented by pairs of cons-lists as described above.)
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
class SymbolJoyType(FunctionJoyType):
|
||||
prefix = 'F'
|
||||
|
||||
For combinators the list contains Python functions.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
need one function and it can be the combinator itself.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
effects.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def branch_true(stack, expression, dictionary):
|
||||
(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,
|
||||
modification to the call structure of ``meta_compose()`` et. al.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
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..)
|
||||
|
||||
|
|
@ -2956,7 +2956,7 @@ module. But if you’re interested in all that you should just use Prolog!
|
|||
|
||||
Anyhow, type *checking* is a few easy steps away.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
def _ge(self, other):
|
||||
return (issubclass(other.__class__, self.__class__)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
it, and rebuild it using the “zipper” technique.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
of sequences.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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,
|
||||
but see below.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('z-down == [] swap uncons swap')
|
||||
define('z-up == swons swap shunt')
|
||||
define('z-right == [swons] cons dip uncons swap')
|
||||
define('z-left == swons [uncons swap] dip swap')
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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 .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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] .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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] .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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”
|
||||
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')
|
||||
|
||||
|
|
@ -270,13 +270,13 @@ been embedded in a nested series of quoted programs, e.g.:
|
|||
|
||||
The ``Z`` function isn’t hard to make.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
define('Z == [[] cons cons] step i')
|
||||
|
||||
Here it is in action in a simplified scenario.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
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.
|
||||
|
||||
.. code:: ipython2
|
||||
.. code:: python
|
||||
|
||||
J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue