Recover the square spiral example code.
I hve no idea how this isn't in VCS. I checked hg and git. Is it in an old branch that I deleted before merging or something? I have backups from which to restore, but it would be nice to know how I effed it up in the first place, eh?
This commit is contained in:
@@ -76,7 +76,7 @@ E.g.:
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
syms = O, l = frozenset({'0'}), frozenset({'1'})
|
||||
|
||||
@@ -123,7 +123,7 @@ expression* is one of:
|
||||
|
||||
Where ``R`` and ``S`` stand for *regular expressions*.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def stringy(re):
|
||||
'''
|
||||
@@ -175,11 +175,11 @@ Match anything. Often spelled “.”
|
||||
|
||||
I = (0|1)*
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
I = (KSTAR, (OR, O, l))
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
print stringy(I)
|
||||
|
||||
@@ -201,14 +201,14 @@ The example expression from Brzozowski:
|
||||
|
||||
Note that it contains one of everything.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def D(symbol):
|
||||
|
||||
@@ -308,7 +308,7 @@ derivation.
|
||||
Compaction Rules
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def _compaction_rule(relation, one, zero, a, b):
|
||||
return (
|
||||
@@ -320,7 +320,7 @@ Compaction Rules
|
||||
|
||||
An elegant symmetry.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# 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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def D_compaction(symbol):
|
||||
|
||||
@@ -414,7 +414,7 @@ Let’s try it out…
|
||||
|
||||
(FIXME: redo.)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
o, z = D_compaction('0'), D_compaction('1')
|
||||
REs = set()
|
||||
@@ -533,10 +533,10 @@ machine transition table.
|
||||
|
||||
Says, “Three or more 1’s and not ending in 01 nor composed of all 1’s.”
|
||||
|
||||
.. figure:: omg.svg
|
||||
:alt: State Machine Graph
|
||||
.. figure:: attachment:omg.svg
|
||||
:alt: omg.svg
|
||||
|
||||
State Machine Graph
|
||||
omg.svg
|
||||
|
||||
Start at ``a`` and follow the transition arrows according to their
|
||||
labels. Accepting states have a double outline. (Graphic generated with
|
||||
@@ -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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from collections import defaultdict
|
||||
from pprint import pprint
|
||||
from string import ascii_lowercase
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
d0, d1 = D_compaction('0'), D_compaction('1')
|
||||
|
||||
``explore()``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def explore(re):
|
||||
|
||||
@@ -645,7 +645,7 @@ disappears once it has been matched.
|
||||
|
||||
return table, accepting
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
table, accepting = explore(it)
|
||||
table
|
||||
@@ -678,7 +678,7 @@ disappears once it has been matched.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
_template = '''\
|
||||
digraph finite_state_machine {
|
||||
@@ -722,7 +722,7 @@ generate the diagram above.
|
||||
)
|
||||
)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def acceptable(input_):
|
||||
return trampoline(input_, a, {h, i})
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
for n in range(2**5):
|
||||
s = bin(n)[2:]
|
||||
|
||||
@@ -3,7 +3,7 @@ Using ``x`` to Generate Values
|
||||
|
||||
Cf. jp-reprod.html
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('direco == dip rest cons')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('G == [direco] cons [swap] swoncat cons')
|
||||
|
||||
Let’s try it out:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('0 [dup ++] G')
|
||||
|
||||
@@ -165,7 +165,7 @@ Let’s try it out:
|
||||
[0 swap [dup ++] direco]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('0 [dup ++] G x x x pop')
|
||||
|
||||
@@ -178,7 +178,7 @@ Let’s try it out:
|
||||
Powers of 2
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('PE1.1 == dup [3 &] dip 2 >>')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
V('14811 PE1.1')
|
||||
|
||||
@@ -252,7 +252,7 @@ int right two bits.
|
||||
|
||||
If we plug ``14811`` and ``[PE1.1]`` into our generator form…
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('PE1.1.check == dup [pop 14811] [] branch')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('14811 [PE1.1.check PE1.1] G')
|
||||
|
||||
@@ -294,7 +294,7 @@ if so.
|
||||
[14811 swap [PE1.1.check PE1.1] direco]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('PE1.2 == + dup [+] dip')
|
||||
|
||||
Now we can add ``PE1.2`` to the quoted program given to ``G``.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('fib == + [popdd over] cons infra uncons')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('fib_gen == [1 1 fib]')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('PE2.1 == dup 2 % [+] [pop] branch')
|
||||
|
||||
And a predicate function that detects when the terms in the series
|
||||
“exceed four million”.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('PE2')
|
||||
|
||||
@@ -535,7 +535,7 @@ So the Fibonacci sequence considered in terms of just parity would be:
|
||||
|
||||
Every third term is even.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('PE2.2 == x x x [popop] dipd')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('codireco == cons dip rest cons')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
V('[0 [dup ++] codireco] x')
|
||||
|
||||
@@ -620,11 +620,11 @@ An Interesting Variation
|
||||
0 [1 [dup ++] codireco] .
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('G == [codireco] cons cons')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('230 [dup ++] G 5 [x] times pop')
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ to write a function that can compute the square root of a number.
|
||||
Cf. `"Why Functional Programming Matters" by John
|
||||
Hughes <https://www.cs.kent.ac.uk/people/staff/dat/miranda/whyfp90.pdf>`__
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
from notebook_preamble import J, V, define
|
||||
|
||||
@@ -75,11 +75,11 @@ The generator can be written as:
|
||||
1 [23 over / + 2 /] [dup] swoncat make_generator
|
||||
1 [dup 23 over / + 2 /] make_generator
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
define('gsra 1 swap [over / + 2 /] cons [dup] swoncat make_generator')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
J('23 gsra')
|
||||
|
||||
@@ -92,7 +92,7 @@ The generator can be written as:
|
||||
Let's drive the generator a few time (with the ``x`` combinator) and
|
||||
square the approximation to see how well it works...
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
J('23 gsra 6 [x popd] times first sqr')
|
||||
|
||||
@@ -142,7 +142,7 @@ Predicate
|
||||
abs(a-b) ε <=
|
||||
(abs(a-b)<=ε)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
define('_within_P [first - abs] dip <=')
|
||||
|
||||
@@ -156,7 +156,7 @@ Base-Case
|
||||
[b G] first
|
||||
b
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
define('_within_B roll< popop first')
|
||||
|
||||
@@ -184,7 +184,7 @@ Pretty straightforward:
|
||||
|
||||
b [c G] ε within
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
define('_within_R [popd x] dip')
|
||||
|
||||
@@ -199,14 +199,14 @@ The recursive function we have defined so far needs a slight preamble:
|
||||
[a G] x ε ...
|
||||
a [b G] ε ...
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
define('within x 0.000000001 [_within_P] [_within_B] [_within_R] tailrec')
|
||||
define('sqrt gsra within')
|
||||
|
||||
Try it out...
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
J('36 sqrt')
|
||||
|
||||
@@ -216,7 +216,7 @@ Try it out...
|
||||
6.0
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
J('23 sqrt')
|
||||
|
||||
@@ -228,7 +228,7 @@ Try it out...
|
||||
|
||||
Check it.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
4.795831523312719**2
|
||||
|
||||
@@ -241,7 +241,7 @@ Check it.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython3
|
||||
|
||||
from math import sqrt
|
||||
|
||||
|
||||
@@ -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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from notebook_preamble import D, J, V, define, DefinitionWrapper
|
||||
|
||||
@@ -87,11 +87,11 @@ Definition:
|
||||
|
||||
Tree-new == swap [[] []] cons cons
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('Tree-new == swap [[] []] cons cons')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('"v" "k" Tree-new')
|
||||
|
||||
@@ -163,11 +163,11 @@ comparison operator:
|
||||
P < == pop roll> pop first <
|
||||
P == pop roll> pop first
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('P == pop roll> pop first')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('["old_key" 23 [] []] 17 "new_key" ["..."] P')
|
||||
|
||||
@@ -242,11 +242,11 @@ And so ``T`` is just:
|
||||
|
||||
T == cons cons [dipdd] cons infra
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('T == cons cons [dipdd] cons infra')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('Te == cons cons [dipd] cons infra')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('Ee == pop swap roll< rest rest cons cons')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec')
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[] 23 "b" Tree-add') # Initial
|
||||
|
||||
@@ -372,7 +372,7 @@ Examples
|
||||
['b' 23 [] []]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('["b" 23 [] []] 88 "c" Tree-add') # Greater than
|
||||
|
||||
@@ -382,7 +382,7 @@ Examples
|
||||
['b' 23 [] ['c' 88 [] []]]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('["b" 23 [] []] 88 "a" Tree-add') # Less than
|
||||
|
||||
@@ -392,7 +392,7 @@ Examples
|
||||
['b' 23 ['a' 88 [] []] []]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('["b" 23 [] []] 88 "b" Tree-add') # Equal to
|
||||
|
||||
@@ -402,7 +402,7 @@ Examples
|
||||
['b' 88 [] []]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step')
|
||||
|
||||
@@ -444,7 +444,7 @@ values:
|
||||
------------------------- a < b
|
||||
L
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("1 0 ['G'] ['E'] ['L'] cmp")
|
||||
|
||||
@@ -454,7 +454,7 @@ values:
|
||||
'G'
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("1 1 ['G'] ['E'] ['L'] cmp")
|
||||
|
||||
@@ -464,7 +464,7 @@ values:
|
||||
'E'
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("0 1 ['G'] ['E'] ['L'] cmp")
|
||||
|
||||
@@ -514,7 +514,7 @@ Or just:
|
||||
|
||||
P == over [popop popop first] nullary
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec')
|
||||
|
||||
Examples
|
||||
~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[] [foo] Tree-iter') # It doesn't matter what F is as it won't be used.
|
||||
|
||||
@@ -702,7 +702,7 @@ Examples
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter")
|
||||
|
||||
@@ -712,7 +712,7 @@ Examples
|
||||
'b' 'a' 'c'
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('to_set == [] swap [0 swap Tree-add] step')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('unique == [to_set [first] Tree-iter] cons run')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
#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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# 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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get')
|
||||
|
||||
@@ -1098,7 +1098,7 @@ So:
|
||||
'mike not in tree'
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('["gary" 23 [] []] "gary" [popop "err"] Tree-get')
|
||||
|
||||
@@ -1108,7 +1108,7 @@ So:
|
||||
23
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('''
|
||||
|
||||
@@ -1124,7 +1124,7 @@ So:
|
||||
2
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('''
|
||||
|
||||
@@ -1500,7 +1500,7 @@ Refactoring
|
||||
By the standards of the code I’ve written so far, this is a *huge* Joy
|
||||
program.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
DefinitionWrapper.add_definitions('''
|
||||
first_two == uncons uncons pop
|
||||
@@ -1519,7 +1519,7 @@ program.
|
||||
Tree-Delete == [pop not] [pop] [R0] [R1] genrec
|
||||
''', D)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ")
|
||||
|
||||
@@ -1529,7 +1529,7 @@ program.
|
||||
['a' 23 [] ['b' 88 [] []]]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ")
|
||||
|
||||
@@ -1539,7 +1539,7 @@ program.
|
||||
['a' 23 [] ['c' 44 [] []]]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ")
|
||||
|
||||
@@ -1549,7 +1549,7 @@ program.
|
||||
['b' 88 [] ['c' 44 [] []]]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ")
|
||||
|
||||
@@ -1559,7 +1559,7 @@ program.
|
||||
['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
|
||||
|
||||
Let’s try it out:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
V('-5 1 4 quadratic')
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
|
||||
|
||||
Let’s try it:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('5 triangular_number')
|
||||
|
||||
@@ -219,7 +219,7 @@ Let’s try it:
|
||||
10
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[0 1 2 3 4 5 6] [triangular_number] map')
|
||||
|
||||
@@ -391,10 +391,8 @@ values.
|
||||
|
||||
A == [P] [] [G] [swons] hylomorphism
|
||||
|
||||
``range`` et. al.
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
An example of an anamorphism is the ``range`` function which generates the list of integers from 0 to *n* - 1 given *n*.
|
||||
``range`` et. al. An example of an anamorphism is the ``range`` function which generates the list of integers from 0 to *n* - 1 given *n*.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Each of the above variations can be used to make four slightly different
|
||||
``range`` functions.
|
||||
@@ -407,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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('5 range')
|
||||
|
||||
@@ -429,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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('5 range_reverse')
|
||||
|
||||
@@ -451,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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('5 ranger')
|
||||
|
||||
@@ -473,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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('5 ranger_reverse')
|
||||
|
||||
@@ -503,7 +501,7 @@ and makes some new value.
|
||||
|
||||
C == [not] c [uncons swap] [F] hylomorphism
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('swuncons == uncons swap') # Awkward name.
|
||||
|
||||
@@ -513,11 +511,11 @@ An example of a catamorphism is the sum function.
|
||||
|
||||
sum == [not] 0 [swuncons] [+] hylomorphism
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('sum == [not] 0 [swuncons] [+] hylomorphism')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[5 4 3 2 1] sum')
|
||||
|
||||
@@ -533,7 +531,7 @@ The ``step`` combinator
|
||||
The ``step`` combinator will usually be better to use than
|
||||
``catamorphism``.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[step] help')
|
||||
|
||||
@@ -562,11 +560,11 @@ The ``step`` combinator will usually be better to use than
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('sum == 0 swap [+] step')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[5 4 3 2 1] sum')
|
||||
|
||||
@@ -594,11 +592,11 @@ With:
|
||||
G == --
|
||||
P == 1 <=
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('5 factorial')
|
||||
|
||||
@@ -637,11 +635,11 @@ We would use:
|
||||
G == rest dup
|
||||
P == not
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from notebook_preamble import D, J, V
|
||||
|
||||
A long trace
|
||||
------------
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
D['size'] = size
|
||||
|
||||
@@ -108,7 +108,7 @@ A shorter trace
|
||||
|
||||
You can see that ``size`` now executes in a single step.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
V('[23 18] average')
|
||||
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
.. code:: ipython3
|
||||
|
||||
from notebook_preamble import J, V, define
|
||||
|
||||
Square Spiral Example Joy Code
|
||||
==============================
|
||||
|
||||
Here is the example of Joy code from the ``README`` file:
|
||||
|
||||
::
|
||||
|
||||
[[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
|
||||
|
||||
It might seem unreadable but with a little familiarity it becomes just
|
||||
as legible as any other notation. Some layout helps:
|
||||
|
||||
::
|
||||
|
||||
[ [[abs] ii <=]
|
||||
[
|
||||
[<>] [pop !-] ||
|
||||
] &&
|
||||
]
|
||||
[[ !-] [[++]] [[--]] ifte dip]
|
||||
[[pop !-] [--] [++] ifte ]
|
||||
ifte
|
||||
|
||||
This function accepts two integers on the stack and increments or
|
||||
decrements one of them such that the new pair of numbers is the next
|
||||
coordinate pair in a square spiral (like the kind used to construct an
|
||||
Ulam Spiral).
|
||||
|
||||
Original Form
|
||||
-------------
|
||||
|
||||
It's adapted from `the original code on
|
||||
StackOverflow <https://stackoverflow.com/questions/398299/looping-in-a-spiral/31864777#31864777>`__:
|
||||
|
||||
If all you're trying to do is generate the first N points in the
|
||||
spiral (without the original problem's constraint of masking to an N
|
||||
x M region), the code becomes very simple:
|
||||
|
||||
::
|
||||
|
||||
void spiral(const int N)
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
for(int i = 0; i < N; ++i)
|
||||
{
|
||||
cout << x << '\t' << y << '\n';
|
||||
if(abs(x) <= abs(y) && (x != y || x >= 0))
|
||||
x += ((y >= 0) ? 1 : -1);
|
||||
else
|
||||
y += ((x >= 0) ? -1 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
Translation to Joy
|
||||
------------------
|
||||
|
||||
I'm going to make a function that take two ints (``x`` and ``y``) and
|
||||
generates the next pair, we'll turn it into a generator later using the
|
||||
``x`` combinator.
|
||||
|
||||
First Boolean Predicate
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We need a function that computes ``abs(x) <= abs(y)``, we can use ``ii``
|
||||
to apply ``abs`` to both values and then compare them with ``<=``:
|
||||
|
||||
::
|
||||
|
||||
[abs] ii <=
|
||||
|
||||
I've defined two short-circuiting Boolean combinators ``&&`` and ``||``
|
||||
that each accept two quoted predicate programs, run the first, and
|
||||
conditionally run the second only if required (to compute the final
|
||||
Boolean value). They run their predicate arguments ``nullary``.
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
define('&& [nullary] cons [nullary [0]] dip branch')
|
||||
define('|| [nullary] cons [nullary] dip [1] branch')
|
||||
|
||||
Given those, we can define ``x != y || x >= 0`` as:
|
||||
|
||||
::
|
||||
|
||||
[<>] [pop 0 >=] ||
|
||||
|
||||
And ``(abs(x) <= abs(y) && (x != y || x >= 0))`` as:
|
||||
|
||||
::
|
||||
|
||||
[[abs] ii <=] [[<>] [pop 0 >=] ||] &&
|
||||
|
||||
It's a little rough, but, as I say, with a little familiarity it becomes
|
||||
legible.
|
||||
|
||||
The Increment / Decrement Branches
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Turning to the branches of the main ``if`` statement:
|
||||
|
||||
::
|
||||
|
||||
x += ((y >= 0) ? 1 : -1);
|
||||
|
||||
Rewrite as a hybrid (pseudo-code) ``ifte`` expression:
|
||||
|
||||
::
|
||||
|
||||
[y >= 0] [x += 1] [X -= 1] ifte
|
||||
|
||||
Change each C phrase to Joy code:
|
||||
|
||||
::
|
||||
|
||||
[0 >=] [[++] dip] [[--] dip] ifte
|
||||
|
||||
Factor out the dip from each branch:
|
||||
|
||||
::
|
||||
|
||||
[0 >=] [[++]] [[--]] ifte dip
|
||||
|
||||
Similar logic applies to the other branch:
|
||||
|
||||
::
|
||||
|
||||
y += ((x >= 0) ? -1 : 1);
|
||||
|
||||
[x >= 0] [y -= 1] [y += 1] ifte
|
||||
|
||||
[pop 0 >=] [--] [++] ifte
|
||||
|
||||
"Not Negative"
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
define('!- 0 >=')
|
||||
|
||||
Putting the Pieces Together
|
||||
---------------------------
|
||||
|
||||
We can assemble the three functions we just defined in quotes and give
|
||||
them them to the ``ifte`` combinator. With some arrangement to show off
|
||||
the symmetry of the two branches, we have:
|
||||
|
||||
::
|
||||
|
||||
[[[abs] ii <=] [[<>] [pop !-] ||] &&]
|
||||
[[ !-] [[++]] [[--]] ifte dip]
|
||||
[[pop !-] [--] [++] ifte ]
|
||||
ifte
|
||||
|
||||
As I was writing this up I realized that, since the ``&&`` combinator
|
||||
doesn't consume the stack (below its quoted args), I can unquote the
|
||||
predicate, swap the branches, and use the ``branch`` combinator instead
|
||||
of ``ifte``:
|
||||
|
||||
::
|
||||
|
||||
[[abs] ii <=] [[<>] [pop !-] ||] &&
|
||||
[[pop !-] [--] [++] ifte ]
|
||||
[[ !-] [[++]] [[--]] ifte dip]
|
||||
branch
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte')
|
||||
|
||||
Let's try it out:
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
J('0 0 spiral_next')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
1 0
|
||||
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
J('1 0 spiral_next')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
1 -1
|
||||
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
J('1 -1 spiral_next')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
0 -1
|
||||
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
J('0 -1 spiral_next')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
-1 -1
|
||||
|
||||
|
||||
Turning it into a Generator with ``x``
|
||||
--------------------------------------
|
||||
|
||||
It can be used with the x combinator to make a kind of generator for
|
||||
spiral square coordinates.
|
||||
|
||||
We can use ``codireco`` to make a generator
|
||||
|
||||
::
|
||||
|
||||
codireco ::= cons dip rest cons
|
||||
|
||||
It will look like this:
|
||||
|
||||
::
|
||||
|
||||
[value [F] codireco]
|
||||
|
||||
Here's a trace of how it works:
|
||||
|
||||
::
|
||||
|
||||
[0 [dup ++] codireco] . x
|
||||
[0 [dup ++] codireco] . 0 [dup ++] codireco
|
||||
[0 [dup ++] codireco] 0 . [dup ++] codireco
|
||||
[0 [dup ++] codireco] 0 [dup ++] . codireco
|
||||
[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
|
||||
[0 [dup ++] codireco] [0 dup ++] . dip rest cons
|
||||
. 0 dup ++ [0 [dup ++] codireco] rest cons
|
||||
0 . dup ++ [0 [dup ++] codireco] rest cons
|
||||
0 0 . ++ [0 [dup ++] codireco] rest cons
|
||||
0 1 . [0 [dup ++] codireco] rest cons
|
||||
0 1 [0 [dup ++] codireco] . rest cons
|
||||
0 1 [[dup ++] codireco] . cons
|
||||
0 [1 [dup ++] codireco] .
|
||||
|
||||
But first we have to change the ``spiral_next`` function to work on a
|
||||
quoted pair of integers, and leave a copy of the pair on the stack.
|
||||
From:
|
||||
|
||||
::
|
||||
|
||||
y x spiral_next
|
||||
---------------------
|
||||
y' x'
|
||||
|
||||
to:
|
||||
|
||||
::
|
||||
|
||||
[x y] [spiral_next] infra
|
||||
-------------------------------
|
||||
[x' y']
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
J('[0 0] [spiral_next] infra')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[0 1]
|
||||
|
||||
|
||||
So our generator is:
|
||||
|
||||
::
|
||||
|
||||
[[x y] [dup [spiral_next] infra] codireco]
|
||||
|
||||
Or rather:
|
||||
|
||||
::
|
||||
|
||||
[[0 0] [dup [spiral_next] infra] codireco]
|
||||
|
||||
There is a function ``make_generator`` that will build the generator for
|
||||
us out of the value and stepper function:
|
||||
|
||||
::
|
||||
|
||||
[0 0] [dup [spiral_next] infra] make_generator
|
||||
----------------------------------------------------
|
||||
[[0 0] [dup [spiral_next] infra] codireco]
|
||||
|
||||
Here it is in action:
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[0 0] [0 1] [-1 1] [-1 0]
|
||||
|
||||
|
||||
Four ``x`` combinators, four pairs of coordinates.
|
||||
|
||||
Conclusion
|
||||
----------
|
||||
|
||||
So that's an example of Joy code. It's a straightforward translation of
|
||||
the original. It's a little long for a single definition, you might
|
||||
break it up like so:
|
||||
|
||||
::
|
||||
|
||||
_spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] &&
|
||||
|
||||
_spn_T ::= [ !-] [[++]] [[--]] ifte dip
|
||||
_spn_E ::= [pop !-] [--] [++] ifte
|
||||
|
||||
spiral_next ::= _spn_P [_spn_E] [_spn_T] branch
|
||||
|
||||
This way it's easy to see that the function is a branch with two
|
||||
quasi-symmetrical paths.
|
||||
|
||||
We then used this function to make a simple generator of coordinate
|
||||
pairs, where the next pair in the series can be generated at any time by
|
||||
using the ``x`` combinator on the generator (which is just a quoted
|
||||
expression containing a copy of the current pair and the "stepper
|
||||
function" to generate the next pair from that.)
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
define('_spn_P [[abs] ii <=] [[<>] [pop !-] ||] &&')
|
||||
define('_spn_T [!-] [[++]] [[--]] ifte dip')
|
||||
define('_spn_E [pop !-] [--] [++] ifte')
|
||||
define('spiral_next _spn_P [_spn_E] [_spn_T] branch')
|
||||
|
||||
.. code:: ipython3
|
||||
|
||||
V('23 18 spiral_next')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
. 23 18 spiral_next
|
||||
23 . 18 spiral_next
|
||||
23 18 . spiral_next
|
||||
23 18 . _spn_P [_spn_E] [_spn_T] branch
|
||||
23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
|
||||
23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch
|
||||
23 18 . 0 [_spn_E] [_spn_T] branch
|
||||
23 18 0 . [_spn_E] [_spn_T] branch
|
||||
23 18 0 [_spn_E] . [_spn_T] branch
|
||||
23 18 0 [_spn_E] [_spn_T] . branch
|
||||
23 18 . _spn_E
|
||||
23 18 . [pop !-] [--] [++] ifte
|
||||
23 18 [pop !-] . [--] [++] ifte
|
||||
23 18 [pop !-] [--] . [++] ifte
|
||||
23 18 [pop !-] [--] [++] . ifte
|
||||
23 18 [pop !-] [--] [++] . [nullary not] dipd branch
|
||||
23 18 [pop !-] [--] [++] [nullary not] . dipd branch
|
||||
23 18 [pop !-] . nullary not [--] [++] branch
|
||||
23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch
|
||||
23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch
|
||||
23 18 [pop !-] [stack] . dip infra first not [--] [++] branch
|
||||
23 18 . stack [pop !-] infra first not [--] [++] branch
|
||||
23 18 [18 23] . [pop !-] infra first not [--] [++] branch
|
||||
23 18 [18 23] [pop !-] . infra first not [--] [++] branch
|
||||
23 18 . pop !- [18 23] swaack first not [--] [++] branch
|
||||
23 . !- [18 23] swaack first not [--] [++] branch
|
||||
23 . 0 >= [18 23] swaack first not [--] [++] branch
|
||||
23 0 . >= [18 23] swaack first not [--] [++] branch
|
||||
True . [18 23] swaack first not [--] [++] branch
|
||||
True [18 23] . swaack first not [--] [++] branch
|
||||
23 18 [True] . first not [--] [++] branch
|
||||
23 18 True . not [--] [++] branch
|
||||
23 18 False . [--] [++] branch
|
||||
23 18 False [--] . [++] branch
|
||||
23 18 False [--] [++] . branch
|
||||
23 18 . --
|
||||
23 17 .
|
||||
|
||||
@@ -148,11 +148,11 @@ Working backwards:
|
||||
Define ``treestep``
|
||||
-------------------
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from notebook_preamble import D, J, V, define, DefinitionWrapper
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
DefinitionWrapper.add_definitions('''
|
||||
|
||||
@@ -173,7 +173,7 @@ all nodes in a tree with this function:
|
||||
|
||||
sumtree == [pop 0] [] [sum +] treestep
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('sumtree == [pop 0] [] [sum +] treestep')
|
||||
|
||||
@@ -185,7 +185,7 @@ Running this function on an empty tree value gives zero:
|
||||
------------------------------------
|
||||
0
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[] sumtree') # Empty tree.
|
||||
|
||||
@@ -205,7 +205,7 @@ Running it on a non-empty node:
|
||||
n m +
|
||||
n+m
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[23] sumtree') # No child trees.
|
||||
|
||||
@@ -215,7 +215,7 @@ Running it on a non-empty node:
|
||||
23
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[23 []] sumtree') # Child tree, empty.
|
||||
|
||||
@@ -225,7 +225,7 @@ Running it on a non-empty node:
|
||||
23
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees.
|
||||
|
||||
@@ -235,7 +235,7 @@ Running it on a non-empty node:
|
||||
32
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc...
|
||||
|
||||
@@ -245,7 +245,7 @@ Running it on a non-empty node:
|
||||
49
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
|
||||
|
||||
@@ -444,7 +444,7 @@ Plugging in our BTree structure:
|
||||
|
||||
Iteration through the nodes
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
DefinitionWrapper.add_definitions('''
|
||||
|
||||
@@ -587,7 +587,7 @@ To me, that seems simpler than the ``genrec`` version.
|
||||
|
||||
''', D)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('''\
|
||||
|
||||
@@ -603,7 +603,7 @@ To me, that seems simpler than the ``genrec`` version.
|
||||
15
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('''\
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Type Checking
|
||||
=============
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
import logging, sys
|
||||
|
||||
@@ -11,7 +11,7 @@ Type Checking
|
||||
level=logging.INFO,
|
||||
)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from joy.utils.types import (
|
||||
doc_from_stack_effect,
|
||||
@@ -22,7 +22,7 @@ Type Checking
|
||||
JoyTypeError,
|
||||
)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
D = FUNCTIONS.copy()
|
||||
del D['product']
|
||||
@@ -31,7 +31,7 @@ Type Checking
|
||||
An Example
|
||||
----------
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
print doc_from_stack_effect(fi, fo)
|
||||
|
||||
@@ -56,13 +56,13 @@ An Example
|
||||
([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from joy.parser import text_to_expression
|
||||
from joy.utils.stack import stack_to_string
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
u = unify(e, fi)[0]
|
||||
u
|
||||
@@ -87,7 +87,7 @@ An Example
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
g = reify(u, (fi, fo))
|
||||
print doc_from_stack_effect(*g)
|
||||
@@ -101,11 +101,11 @@ An Example
|
||||
Unification Works “in Reverse”
|
||||
------------------------------
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
e = text_to_expression('[2 3]')
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
u = unify(e, fo)[0] # output side, not input side
|
||||
u
|
||||
@@ -119,7 +119,7 @@ Unification Works “in Reverse”
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
g = reify(u, (fi, fo))
|
||||
print doc_from_stack_effect(*g)
|
||||
@@ -133,7 +133,7 @@ Unification Works “in Reverse”
|
||||
Failing a Check
|
||||
---------------
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
fi, fo = infer(dup, mul)[0]
|
||||
|
||||
@@ -146,7 +146,7 @@ Failing a Check
|
||||
31 (i1 -- i2) ∘
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
e = text_to_expression('"two"')
|
||||
print stack_to_string(e)
|
||||
@@ -157,7 +157,7 @@ Failing a Check
|
||||
'two'
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
try:
|
||||
unify(e, fi)
|
||||
|
||||
@@ -184,7 +184,7 @@ Compiling ``pop∘swap∘roll<``
|
||||
|
||||
The simplest way to “compile” this function would be something like:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
roll_dn = (1, 2, 3), (2, 3, 1)
|
||||
|
||||
@@ -419,7 +419,7 @@ integers or tuples of type descriptors:
|
||||
``compose()``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def compose(f, g):
|
||||
|
||||
@@ -465,7 +465,7 @@ integers or tuples of type descriptors:
|
||||
``unify()``
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def unify(u, v, s=None):
|
||||
if s is None:
|
||||
@@ -483,7 +483,7 @@ integers or tuples of type descriptors:
|
||||
``update()``
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def update(s, term):
|
||||
if not isinstance(term, tuple):
|
||||
@@ -493,7 +493,7 @@ integers or tuples of type descriptors:
|
||||
``relabel()``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def relabel(left, right):
|
||||
return left, _1000(right)
|
||||
@@ -517,7 +517,7 @@ integers or tuples of type descriptors:
|
||||
``delabel()``
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(pop, swap)
|
||||
|
||||
@@ -573,7 +573,7 @@ Let’s try it out.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(C(pop, swap), roll_dn)
|
||||
|
||||
@@ -586,7 +586,7 @@ Let’s try it out.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(swap, roll_dn)
|
||||
|
||||
@@ -599,7 +599,7 @@ Let’s try it out.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(pop, C(swap, roll_dn))
|
||||
|
||||
@@ -612,7 +612,7 @@ Let’s try it out.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
rest = ((1, 2),), (2,)
|
||||
|
||||
cons = (1, 2), ((1, 2),)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(poswrd, rest)
|
||||
|
||||
@@ -671,7 +671,7 @@ The translation table, if you will, would be:
|
||||
0: 0,
|
||||
}
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
uncons = ((1, 2),), (1, 2)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def unify(u, v, s=None):
|
||||
if s is None:
|
||||
@@ -753,7 +753,7 @@ deal with this recursively:
|
||||
|
||||
return s
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(cons, uncons)
|
||||
|
||||
@@ -771,7 +771,7 @@ Part III: Compiling Yin Functions
|
||||
|
||||
Now consider the Python function we would like to derive:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
F[0]
|
||||
|
||||
@@ -816,7 +816,7 @@ Eh?
|
||||
|
||||
And the return tuple
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def compile_(name, f, doc=None):
|
||||
if doc is None:
|
||||
@@ -932,7 +932,7 @@ function.)
|
||||
|
||||
Here it is in action:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
source = compile_('F', F)
|
||||
|
||||
@@ -949,7 +949,7 @@ Here it is in action:
|
||||
|
||||
Compare:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def F_python(stack):
|
||||
(_, (d, (c, ((a, (b, S0)), stack)))) = stack
|
||||
@@ -957,7 +957,7 @@ Compare:
|
||||
|
||||
Next steps:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
L = {}
|
||||
|
||||
@@ -976,16 +976,16 @@ Next steps:
|
||||
|
||||
Let’s try it out:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from notebook_preamble import D, J, V
|
||||
from joy.library import SimpleFunctionWrapper
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
D['F'] = SimpleFunctionWrapper(L['F'])
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def defs():
|
||||
|
||||
@@ -1036,7 +1036,7 @@ from their stack effect comments:
|
||||
|
||||
return locals()
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
class AnyJoyType(object):
|
||||
|
||||
@@ -1251,14 +1251,14 @@ make it fairly easy to reuse most of the code above.
|
||||
|
||||
Mess with it a little:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
from itertools import permutations
|
||||
|
||||
“Any” types can be specialized to numbers and stacks, but not vice
|
||||
versa:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
dup = (A[1],), (A[1], A[1])
|
||||
|
||||
mul = (N[1], N[2]), (N[3],)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
dup
|
||||
|
||||
@@ -1322,7 +1322,7 @@ Typing ``sqr``
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
mul
|
||||
|
||||
@@ -1340,7 +1340,7 @@ Modifying the Inferencer
|
||||
|
||||
Re-labeling still works fine:
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
delabel(foo)
|
||||
|
||||
@@ -1399,7 +1399,7 @@ of how many labels of each domain it has “seen”.
|
||||
``unify()`` version 3
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def defs():
|
||||
|
||||
@@ -1503,11 +1503,11 @@ Rewrite the stack effect comments:
|
||||
|
||||
return locals()
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
DEFS = defs()
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
globals().update(DEFS)
|
||||
|
||||
Compose ``dup`` and ``mul``
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(dup, mul)
|
||||
|
||||
@@ -1565,7 +1565,7 @@ Compose ``dup`` and ``mul``
|
||||
|
||||
Revisit the ``F`` function, works fine.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
|
||||
F
|
||||
@@ -1579,7 +1579,7 @@ Revisit the ``F`` function, works fine.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
def neato(*funcs):
|
||||
print doc_from_stack_effect(*reduce(C, funcs))
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# 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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# 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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
# 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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(stack, uncons)
|
||||
|
||||
@@ -1867,7 +1867,7 @@ conversion function instead. This is programmer’s laziness.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
print compile_('Q', Q)
|
||||
|
||||
@@ -2053,12 +2053,12 @@ comments are now already in the form needed for the Python code:
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
unstack = (S[1], S[0]), S[1]
|
||||
enstacken = S[0], (S[0], S[1])
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
print doc_from_stack_effect(*unstack)
|
||||
|
||||
@@ -2068,7 +2068,7 @@ comments are now already in the form needed for the Python code:
|
||||
([.1.] --)
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
print doc_from_stack_effect(*enstacken)
|
||||
|
||||
@@ -2078,7 +2078,7 @@ comments are now already in the form needed for the Python code:
|
||||
(-- [.0.])
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
C(cons, unstack)
|
||||
|
||||
@@ -2117,7 +2117,7 @@ Part VI: Multiple Stack Effects
|
||||
|
||||
…
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
class IntJoyType(NumberJoyType): prefix = 'i'
|
||||
|
||||
@@ -2125,7 +2125,7 @@ Part VI: Multiple Stack Effects
|
||||
F = map(FloatJoyType, _R)
|
||||
I = map(IntJoyType, _R)
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
for f in muls:
|
||||
print doc_from_stack_effect(*f)
|
||||
@@ -2148,7 +2148,7 @@ Part VI: Multiple Stack Effects
|
||||
(f1 f2 -- f3)
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
for f in muls:
|
||||
try:
|
||||
@@ -2164,7 +2164,7 @@ Part VI: Multiple Stack Effects
|
||||
(a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2)
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
for f in MC([dup], [mul]):
|
||||
print doc_from_stack_effect(*f)
|
||||
@@ -2191,7 +2191,7 @@ Part VI: Multiple Stack Effects
|
||||
(n1 -- n2)
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
class KleeneStar(object):
|
||||
|
||||
@@ -2314,7 +2314,7 @@ Giving us two unifiers:
|
||||
|
||||
Can now return multiple results…
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
a = (As[1], S[1])
|
||||
a
|
||||
@@ -2400,7 +2400,7 @@ Can now return multiple results…
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
b = (A[1], S[2])
|
||||
b
|
||||
@@ -2414,7 +2414,7 @@ Can now return multiple results…
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0])
|
||||
|
||||
@@ -2458,7 +2458,7 @@ Can now return multiple results…
|
||||
([n1* .1.] -- n0)
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
|
||||
|
||||
@@ -2542,7 +2542,7 @@ This function has to be modified to yield multiple results.
|
||||
([n1* .1.] -- [n1* .1.] n1)
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
|
||||
|
||||
@@ -2556,7 +2556,7 @@ This function has to be modified to yield multiple results.
|
||||
(n1 [n1* .1.] -- n2)
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
b = (A[1], (A[2], S[2]))
|
||||
b
|
||||
@@ -2599,7 +2599,7 @@ This function has to be modified to yield multiple results.
|
||||
|
||||
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
class SymbolJoyType(FunctionJoyType):
|
||||
prefix = 'F'
|
||||
|
||||
For combinators the list contains Python functions.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
define('Z == [[] cons cons] step i')
|
||||
|
||||
Here it is in action in a simplified scenario.
|
||||
|
||||
.. code:: python
|
||||
.. code:: ipython2
|
||||
|
||||
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:: python
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z')
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ These essays are adapted from Jupyter notebooks. I hope to have those hosted so
|
||||
Treestep
|
||||
Generator_Programs
|
||||
Newton-Raphson
|
||||
Square_Spiral
|
||||
Zipper
|
||||
Types
|
||||
TypeChecking
|
||||
|
||||
Reference in New Issue
Block a user