Notebooks in Sphinx?
Converting the notebooks to ReST with nbconvert, then using sphinx on the .rst files gives a pretty decent effect, except that the title levels are off a little. I need to look into hosting for the notebooks, maybe on MS Azure. In the meantime, I prefer the HTML made by Sphinx to the HTML made by nbconvert directly. It has index and cross refs and the code blocks scroll horizontally which is crucial for wide Joy traces. And Garamond. God bless Garamond. For the Sphinx docs I'm going to edit the notebook ReST files by hand, diverging from the originals.
This commit is contained in:
@@ -0,0 +1,353 @@
|
||||
|
||||
This notebook is about using the "zipper" with joy datastructures. See
|
||||
the `Zipper wikipedia
|
||||
entry <https://en.wikipedia.org/wiki/Zipper_%28data_structure%29>`__ or
|
||||
the original paper: `"FUNCTIONAL PEARL The Zipper" by Gérard
|
||||
Huet <https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf>`__
|
||||
|
||||
Given a datastructure on the stack we can navigate through it, modify
|
||||
it, and rebuild it using the "zipper" technique.
|
||||
|
||||
Preamble
|
||||
~~~~~~~~
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
from notebook_preamble import J, V, define
|
||||
|
||||
Trees
|
||||
-----
|
||||
|
||||
In Joypy there aren't any complex datastructures, just ints, floats,
|
||||
strings, Symbols (strings that are names of functions) and sequences
|
||||
(aka lists, aka quoted literals, aka aggregates, etc...), but we can
|
||||
build
|
||||
`trees <https://en.wikipedia.org/wiki/Tree_%28data_structure%29>`__ out
|
||||
of sequences.
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1 [2 [3 4 25 6] 7] 8]')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1 [2 [3 4 25 6] 7] 8]
|
||||
|
||||
|
||||
Zipper in Joy
|
||||
-------------
|
||||
|
||||
Zippers work by keeping track of the current item, the already-seen
|
||||
items, and the yet-to-be seen items as you traverse a datastructure (the
|
||||
datastructure used to keep track of these items is the zipper.)
|
||||
|
||||
In Joy we can do this with the following words:
|
||||
|
||||
::
|
||||
|
||||
z-down == [] swap uncons swap
|
||||
z-up == swons swap shunt
|
||||
z-right == [swons] cons dip uncons swap
|
||||
z-left == swons [uncons swap] dip swap
|
||||
|
||||
Let's use them to change 25 into 625. The first time a word is used I
|
||||
show the trace so you can see how it works. If we were going to use
|
||||
these a lot it would make sense to write Python versions for efficiency,
|
||||
but see below.
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
define('z-down == [] swap uncons swap')
|
||||
define('z-up == swons swap shunt')
|
||||
define('z-right == [swons] cons dip uncons swap')
|
||||
define('z-left == swons [uncons swap] dip swap')
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
V('[1 [2 [3 4 25 6] 7] 8] z-down')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
. [1 [2 [3 4 25 6] 7] 8] z-down
|
||||
[1 [2 [3 4 25 6] 7] 8] . z-down
|
||||
[1 [2 [3 4 25 6] 7] 8] . [] swap uncons swap
|
||||
[1 [2 [3 4 25 6] 7] 8] [] . swap uncons swap
|
||||
[] [1 [2 [3 4 25 6] 7] 8] . uncons swap
|
||||
[] 1 [[2 [3 4 25 6] 7] 8] . swap
|
||||
[] [[2 [3 4 25 6] 7] 8] 1 .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
V('[] [[2 [3 4 25 6] 7] 8] 1 z-right')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
. [] [[2 [3 4 25 6] 7] 8] 1 z-right
|
||||
[] . [[2 [3 4 25 6] 7] 8] 1 z-right
|
||||
[] [[2 [3 4 25 6] 7] 8] . 1 z-right
|
||||
[] [[2 [3 4 25 6] 7] 8] 1 . z-right
|
||||
[] [[2 [3 4 25 6] 7] 8] 1 . [swons] cons dip uncons swap
|
||||
[] [[2 [3 4 25 6] 7] 8] 1 [swons] . cons dip uncons swap
|
||||
[] [[2 [3 4 25 6] 7] 8] [1 swons] . dip uncons swap
|
||||
[] . 1 swons [[2 [3 4 25 6] 7] 8] uncons swap
|
||||
[] 1 . swons [[2 [3 4 25 6] 7] 8] uncons swap
|
||||
[] 1 . swap cons [[2 [3 4 25 6] 7] 8] uncons swap
|
||||
1 [] . cons [[2 [3 4 25 6] 7] 8] uncons swap
|
||||
[1] . [[2 [3 4 25 6] 7] 8] uncons swap
|
||||
[1] [[2 [3 4 25 6] 7] 8] . uncons swap
|
||||
[1] [2 [3 4 25 6] 7] [8] . swap
|
||||
[1] [8] [2 [3 4 25 6] 7] .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1] [8] [2 [3 4 25 6] 7] z-down')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1] [8] [] [[3 4 25 6] 7] 2
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1] [8] [] [[3 4 25 6] 7] 2 z-right')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1] [8] [2] [7] [3 4 25 6]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1] [8] [2] [7] [3 4 25 6] z-down')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1] [8] [2] [7] [] [4 25 6] 3
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1] [8] [2] [7] [] [4 25 6] 3 z-right')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1] [8] [2] [7] [3] [25 6] 4
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1] [8] [2] [7] [3] [25 6] 4 z-right')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1] [8] [2] [7] [4 3] [6] 25
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1] [8] [2] [7] [4 3] [6] 25 sqr')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1] [8] [2] [7] [4 3] [6] 625
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
V('[1] [8] [2] [7] [4 3] [6] 625 z-up')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
. [1] [8] [2] [7] [4 3] [6] 625 z-up
|
||||
[1] . [8] [2] [7] [4 3] [6] 625 z-up
|
||||
[1] [8] . [2] [7] [4 3] [6] 625 z-up
|
||||
[1] [8] [2] . [7] [4 3] [6] 625 z-up
|
||||
[1] [8] [2] [7] . [4 3] [6] 625 z-up
|
||||
[1] [8] [2] [7] [4 3] . [6] 625 z-up
|
||||
[1] [8] [2] [7] [4 3] [6] . 625 z-up
|
||||
[1] [8] [2] [7] [4 3] [6] 625 . z-up
|
||||
[1] [8] [2] [7] [4 3] [6] 625 . swons swap shunt
|
||||
[1] [8] [2] [7] [4 3] [6] 625 . swap cons swap shunt
|
||||
[1] [8] [2] [7] [4 3] 625 [6] . cons swap shunt
|
||||
[1] [8] [2] [7] [4 3] [625 6] . swap shunt
|
||||
[1] [8] [2] [7] [625 6] [4 3] . shunt
|
||||
[1] [8] [2] [7] [3 4 625 6] .
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1] [8] [2] [7] [3 4 625 6] z-up')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1] [8] [2 [3 4 625 6] 7]
|
||||
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1] [8] [2 [3 4 625 6] 7] z-up')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1 [2 [3 4 625 6] 7] 8]
|
||||
|
||||
|
||||
``dip`` and ``infra``
|
||||
---------------------
|
||||
|
||||
In Joy we have the ``dip`` and ``infra`` combinators which can "target"
|
||||
or "address" any particular item in a Joy tree structure.
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
. [1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra
|
||||
[1 [2 [3 4 25 6] 7] 8] . [[[[[[sqr] dipd] infra] dip] infra] dip] infra
|
||||
[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] . infra
|
||||
8 [2 [3 4 25 6] 7] 1 . [[[[[sqr] dipd] infra] dip] infra] dip [] swaack
|
||||
8 [2 [3 4 25 6] 7] 1 [[[[[sqr] dipd] infra] dip] infra] . dip [] swaack
|
||||
8 [2 [3 4 25 6] 7] . [[[[sqr] dipd] infra] dip] infra 1 [] swaack
|
||||
8 [2 [3 4 25 6] 7] [[[[sqr] dipd] infra] dip] . infra 1 [] swaack
|
||||
7 [3 4 25 6] 2 . [[[sqr] dipd] infra] dip [8] swaack 1 [] swaack
|
||||
7 [3 4 25 6] 2 [[[sqr] dipd] infra] . dip [8] swaack 1 [] swaack
|
||||
7 [3 4 25 6] . [[sqr] dipd] infra 2 [8] swaack 1 [] swaack
|
||||
7 [3 4 25 6] [[sqr] dipd] . infra 2 [8] swaack 1 [] swaack
|
||||
6 25 4 3 . [sqr] dipd [7] swaack 2 [8] swaack 1 [] swaack
|
||||
6 25 4 3 [sqr] . dipd [7] swaack 2 [8] swaack 1 [] swaack
|
||||
6 25 . sqr 4 3 [7] swaack 2 [8] swaack 1 [] swaack
|
||||
6 25 . dup mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack
|
||||
6 25 25 . mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack
|
||||
6 625 . 4 3 [7] swaack 2 [8] swaack 1 [] swaack
|
||||
6 625 4 . 3 [7] swaack 2 [8] swaack 1 [] swaack
|
||||
6 625 4 3 . [7] swaack 2 [8] swaack 1 [] swaack
|
||||
6 625 4 3 [7] . swaack 2 [8] swaack 1 [] swaack
|
||||
7 [3 4 625 6] . 2 [8] swaack 1 [] swaack
|
||||
7 [3 4 625 6] 2 . [8] swaack 1 [] swaack
|
||||
7 [3 4 625 6] 2 [8] . swaack 1 [] swaack
|
||||
8 [2 [3 4 625 6] 7] . 1 [] swaack
|
||||
8 [2 [3 4 625 6] 7] 1 . [] swaack
|
||||
8 [2 [3 4 625 6] 7] 1 [] . swaack
|
||||
[1 [2 [3 4 625 6] 7] 8] .
|
||||
|
||||
|
||||
If you read the trace carefully you'll see that about half of it is the
|
||||
``dip`` and ``infra`` combinators de-quoting programs and "digging" into
|
||||
the subject datastructure. Instead of maintaining temporary results on
|
||||
the stack they are pushed into the pending expression (continuation).
|
||||
When ``sqr`` has run the rest of the pending expression rebuilds the
|
||||
datastructure.
|
||||
|
||||
``Z``
|
||||
-----
|
||||
|
||||
Imagine a function ``Z`` that accepts a sequence of ``dip`` and
|
||||
``infra`` combinators, a quoted program ``[Q]``, and a datastructure to
|
||||
work on. It would effectively execute the quoted program as if it had
|
||||
been embedded in a nested series of quoted programs, e.g.:
|
||||
|
||||
::
|
||||
|
||||
[...] [Q] [dip dip infra dip infra dip infra] Z
|
||||
-------------------------------------------------------------
|
||||
[...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra
|
||||
|
||||
|
||||
The ``Z`` function isn't hard to make.
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
define('Z == [[] cons cons] step i')
|
||||
|
||||
Here it is in action in a simplified scenario.
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
V('1 [2 3 4] Z')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
. 1 [2 3 4] Z
|
||||
1 . [2 3 4] Z
|
||||
1 [2 3 4] . Z
|
||||
1 [2 3 4] . [[] cons cons] step i
|
||||
1 [2 3 4] [[] cons cons] . step i
|
||||
1 2 [[] cons cons] . i [3 4] [[] cons cons] step i
|
||||
1 2 . [] cons cons [3 4] [[] cons cons] step i
|
||||
1 2 [] . cons cons [3 4] [[] cons cons] step i
|
||||
1 [2] . cons [3 4] [[] cons cons] step i
|
||||
[1 2] . [3 4] [[] cons cons] step i
|
||||
[1 2] [3 4] . [[] cons cons] step i
|
||||
[1 2] [3 4] [[] cons cons] . step i
|
||||
[1 2] 3 [[] cons cons] . i [4] [[] cons cons] step i
|
||||
[1 2] 3 . [] cons cons [4] [[] cons cons] step i
|
||||
[1 2] 3 [] . cons cons [4] [[] cons cons] step i
|
||||
[1 2] [3] . cons [4] [[] cons cons] step i
|
||||
[[1 2] 3] . [4] [[] cons cons] step i
|
||||
[[1 2] 3] [4] . [[] cons cons] step i
|
||||
[[1 2] 3] [4] [[] cons cons] . step i
|
||||
[[1 2] 3] 4 [[] cons cons] . i i
|
||||
[[1 2] 3] 4 . [] cons cons i
|
||||
[[1 2] 3] 4 [] . cons cons i
|
||||
[[1 2] 3] [4] . cons i
|
||||
[[[1 2] 3] 4] . i
|
||||
. [[1 2] 3] 4
|
||||
[[1 2] 3] . 4
|
||||
[[1 2] 3] 4 .
|
||||
|
||||
|
||||
And here it is doing the main thing.
|
||||
|
||||
.. code:: ipython2
|
||||
|
||||
J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z')
|
||||
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
[1 [2 [3 4 625 6] 7] 8]
|
||||
|
||||
|
||||
Addressing
|
||||
----------
|
||||
|
||||
Because we are only using two combinators we could replace the list with
|
||||
a string made from only two characters.
|
||||
|
||||
::
|
||||
|
||||
[...] [Q] 'ddididi' Zstr
|
||||
-------------------------------------------------------------
|
||||
[...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra
|
||||
|
||||
The string can be considered a name or address for an item in the
|
||||
subject datastructure.
|
||||
|
||||
Determining the right "path" for an item in a tree.
|
||||
---------------------------------------------------
|
||||
|
||||
It's easy to read off (in reverse) the right sequence of "d" and "i"
|
||||
from the subject datastructure:
|
||||
|
||||
::
|
||||
|
||||
[ n [ n [ n n x ...
|
||||
i d i d i d d Bingo!
|
||||
Reference in New Issue
Block a user