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:
Simon Forman
2021-11-27 09:04:25 -08:00
parent f96013d649
commit 1b193b1924
63 changed files with 17476 additions and 1013 deletions
@@ -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.
Lets 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 @@ Lets 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 1s and not ending in 01 nor composed of all 1s.”
.. 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`` isnt.
.. 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
Lets try it:
.. code:: python
.. code:: ipython2
V('[0 swap [dup ++] dip rest cons] x')
@@ -81,7 +81,7 @@ Lets try it:
After one application of ``x`` the quoted program contains ``1`` and
``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')
Lets try it out:
.. code:: python
.. code:: ipython2
J('0 [dup ++] G')
@@ -165,7 +165,7 @@ Lets try it out:
[0 swap [dup ++] direco]
.. code:: python
.. code:: ipython2
J('0 [dup ++] G x x x pop')
@@ -178,7 +178,7 @@ Lets 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. Its 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 its 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')
+12 -12
View File
@@ -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 @@ Lets 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 Ive 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 ")
+4 -4
View File
@@ -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 its the definition of the ``quadratic`` function:
.. code:: python
.. code:: ipython2
define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
Lets 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')
Lets try it:
.. code:: python
.. code:: ipython2
J('5 triangular_number')
@@ -219,7 +219,7 @@ Lets 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')
+5 -5
View File
@@ -9,14 +9,14 @@ dictionary. However, theres no function that does that. Adding a new
function to the dictionary is a meta-interpreter action, you have to do
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 .
+24 -24
View File
@@ -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 doesnt 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('''\
+15 -15
View File
@@ -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)
+114 -114
View File
@@ -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
Im 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 cant 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 cant be composed due to type conflicts.)
Lets try it out.
.. code:: python
.. code:: ipython2
C(pop, swap)
@@ -573,7 +573,7 @@ Lets try it out.
.. code:: python
.. code:: ipython2
C(C(pop, swap), roll_dn)
@@ -586,7 +586,7 @@ Lets try it out.
.. code:: python
.. code:: ipython2
C(swap, roll_dn)
@@ -599,7 +599,7 @@ Lets try it out.
.. code:: python
.. code:: ipython2
C(pop, C(swap, roll_dn))
@@ -612,7 +612,7 @@ Lets try it out.
.. code:: python
.. code:: ipython2
poswrd = reduce(C, (pop, swap, roll_dn))
poswrd
@@ -633,13 +633,13 @@ Heres that trick to represent functions like ``rest`` and ``cons`` that
manipulate stacks. We use a cons-list of tuples and give the tails their
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 wont
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 doesnt 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. Im 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 youre 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:
Lets 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 were 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 doesnt 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 doesnt 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 doesnt 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 dont want to rewrite all the defs myself, so Ill write a little
conversion function instead. This is programmers 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 programmers 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 programmers 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 youre 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__)
+18 -18
View File
@@ -10,7 +10,7 @@ Huet <https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-
Given a datastructure on the stack we can navigate through it, modify
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 isnt 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')
+1
View File
@@ -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