From a69b7e2a5618bbc22eaf2adc3466e128a47b54b0 Mon Sep 17 00:00:00 2001 From: Simon Forman Date: Fri, 19 Nov 2021 13:59:00 -0800 Subject: [PATCH] Still converting syntax highlighter spec. --- .../sphinx_docs/_build/doctrees/environment.pickle | Bin 288221 -> 287893 bytes docs/sphinx_docs/_build/doctrees/lib.doctree | Bin 95859 -> 95605 bytes .../Derivatives_of_Regular_Expressions.doctree | Bin 67519 -> 67463 bytes .../_build/doctrees/notebooks/Developing.doctree | Bin 66745 -> 66675 bytes .../doctrees/notebooks/Generator_Programs.doctree | Bin 48705 -> 48629 bytes .../_build/doctrees/notebooks/Intro.doctree | Bin 40979 -> 40965 bytes .../notebooks/Ordered_Binary_Trees.doctree | Bin 133162 -> 133064 bytes .../_build/doctrees/notebooks/Quadratic.doctree | Bin 20417 -> 20409 bytes .../notebooks/Recursion_Combinators.doctree | Bin 70371 -> 70323 bytes .../_build/doctrees/notebooks/Replacing.doctree | Bin 30615 -> 30605 bytes .../_build/doctrees/notebooks/Treestep.doctree | Bin 48208 -> 48160 bytes .../_build/doctrees/notebooks/TypeChecking.doctree | Bin 9272 -> 9242 bytes .../_build/doctrees/notebooks/Types.doctree | Bin 202616 -> 202388 bytes .../_build/doctrees/notebooks/Zipper.doctree | Bin 33430 -> 33394 bytes docs/sphinx_docs/_build/html/_sources/lib.rst.txt | 254 ++-- .../Derivatives_of_Regular_Expressions.rst.txt | 56 +- .../html/_sources/notebooks/Developing.rst.txt | 70 +- .../_sources/notebooks/Generator_Programs.rst.txt | 76 +- .../_build/html/_sources/notebooks/Intro.rst.txt | 14 +- .../notebooks/Ordered_Binary_Trees.rst.txt | 98 +- .../html/_sources/notebooks/Quadratic.rst.txt | 8 +- .../notebooks/Recursion_Combinators.rst.txt | 48 +- .../html/_sources/notebooks/Replacing.rst.txt | 10 +- .../html/_sources/notebooks/Treestep.rst.txt | 48 +- .../html/_sources/notebooks/TypeChecking.rst.txt | 30 +- .../_build/html/_sources/notebooks/Types.rst.txt | 228 ++-- .../_build/html/_sources/notebooks/Zipper.rst.txt | 36 +- docs/sphinx_docs/_build/html/lib.html | 258 ++-- .../Derivatives_of_Regular_Expressions.html | 498 +++---- .../_build/html/notebooks/Developing.html | 70 +- .../_build/html/notebooks/Generator_Programs.html | 76 +- docs/sphinx_docs/_build/html/notebooks/Intro.html | 18 +- .../html/notebooks/Ordered_Binary_Trees.html | 182 +-- .../_build/html/notebooks/Quadratic.html | 8 +- .../html/notebooks/Recursion_Combinators.html | 66 +- .../_build/html/notebooks/Replacing.html | 28 +- .../_build/html/notebooks/Treestep.html | 82 +- .../_build/html/notebooks/TypeChecking.html | 78 +- docs/sphinx_docs/_build/html/notebooks/Types.html | 1430 ++++++++++---------- docs/sphinx_docs/_build/html/notebooks/Zipper.html | 42 +- docs/sphinx_docs/notebooks/Newton-Raphson.rst | 24 +- 41 files changed, 1918 insertions(+), 1918 deletions(-) diff --git a/docs/sphinx_docs/_build/doctrees/environment.pickle b/docs/sphinx_docs/_build/doctrees/environment.pickle index df73e23e05d147362eef718da7efdbbaa28980c0..f0907159c0b478a8cfe9e8a6e3b05c78f70a993b 100644 GIT binary patch literal 287893 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

%|s5%OKyj7V<$ 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 J+U=#n{|{uBa9IEV literal 288221 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 diff --git a/docs/sphinx_docs/_build/doctrees/lib.doctree b/docs/sphinx_docs/_build/doctrees/lib.doctree index 681efe5385d8144787dc855e41caca1ccbce7dd4..785d5bb54e27dd01bc06f87a6484a0b811683447 100644 GIT binary patch delta 1725 zcmYjRYeJNHfti(yi80Sym!%9$xR-&6+nEh;+hZICd7foXtY+26 z6|yy7HvqZH3kky2JHVuA;^9^wJP4oaNx zGgb$niz|oq*dZSU`!`9Vz%q1EFG+$W@`atr#&DG&RgOblLBr51(g83g`NP@=4jM7oy`D~d#(yQ zcwgKK*$pcP!pf!~`+YGA2K&oH017I$15{m>0W?-}+Znu4!p(Cn5lxF~6acl?djO*A zoZ*&Izrfzf6Zg<*OdqRvJg> zyCg8BAGmAY@$s#a$?7($MYf@2NzO^{WLxmO>8e^k7{-0)%*|EP>C9Y9Y*X=`X(%~oD=#e~ypUNEQfVzSmy)8EWnzX3DlHXn zh-i38LS1@9DY_|%&J4O4l9fmoB8V&q)PlbFoPGQ8Jm-C%^Zw5{`}Ni4=QkT+v9Q*v zU)UuOi_V-cxL`15?J%1K**1W_q8q3_u@e%g&m?o}00(5bs0KKtAlAr7u~dRft~IQk zR!GqNe#-{LCFN#J<)m^z)laR#%0|y##BJV=Xx8`~#=edIn@}ANa6^0-n2xwVC=B;o z9vY77WLPMocvm4ds)$ga+N)I}&P1-D`NdvmRDVQqTad(X+gHV&!~NFl=P_ha9JjVU zUWS$X61YZ|L_Mm?Luw&>qkTt0u~AuyKjO$SIhtP`pG9>jO^TJL(u)w|PP-r)4Z*m! zJ0lTQ>&z=St8!xln!R&4oVYNK=DPeKEHz!=jksE9k0`$+LR1%Vlhj_$#{CYJL}HBP zQYoVBdI#dYa$BrCS@9e~n%b*YVd`Dg6Cj%NP1d-ytZno{b7m8_-R5Q^ zhLW`^5JTD=5f8T8A*SBCjg1_-xyrhp2As`@JKW81>*FqWaDN$wd@xXrm~>Z+cxtd4 zV>l1HVGPaaMZ2}pwcj7ZrDNj~^uC^G!b$~G+=*PV%%i$6Xqm;aOm10@@Al1ha@}1jfUv){{!QR*nrTNCiPVKPm|(!oIlER+s_X zsG{v)XVD&{hbNrX`cN$D3x3pQ3+*aH2p?Bw*-5S#_j@=6Vn1~R)gwRBk}vX7BXH5f`BbVS diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Derivatives_of_Regular_Expressions.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Derivatives_of_Regular_Expressions.doctree index c5f972581a0385fd58f0d8ea8d00afdcd100dc5b..165ff02932c2b39e1ce55eb0d97a2eb8dd186618 100644 GIT binary patch delta 393 zcmdnr&(hw{!qUJpRd^%IDKU1og36MN{JhQA#l)E5oNtnK>~K!4;&uebR?~+YE;GqQ z1FmQCVe_SMi9!osRv2gUaogoE_U3ZC-5hX^wfiY9IEOFD18&yl_)tFtXIn%I!hYuj z4ut(7+45{~18NGR9bufw4>mo3u{WRG{0!lk9Xrp#CHi+YA#9P_w*+q1AWt$0_QBct%~r>g~ylRwrpPgQjQU>?9wYY(W#1zcAQfa*crfJYdm8DI{@}G Bl4t+` delta 449 zcmZqgXW8G+!qUJpm3Je{DKSot%!102jQl*K%~!?5n31@jBQ89(ljtK7LeVZO2c$=4QeunJCNjuLWNv7{=Lbmn8-X%!pPM&?_ z6q4GUqt679xRKWdSdh2{w^flnJLmBwBwII^zLaA`QatOGn<(ehdF%{eF!{lMyRGVs G3G4ur(xh1c diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Developing.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Developing.doctree index c628a79cf4e8e52a5573756c0d5a12bbf3c78b14..5204cb89b4af78b2a3052400cbd151a0b2f7a332 100644 GIT binary patch delta 493 zcmdnl$?~~_g{6UID#Jz=9}af5g36MN{JhPP97-%O&g2%JJ{WtmG;f3yj5E1LeG!bk zSzV)(3C`K6HB}MDnH=u(6UN>g>C4Cn=Op{(BedKO5N3wSO#U7`8OGi`IYgWt&e(I*w)$|kp5oC-Ht=@K)- z$9gxvBTUx2{S^^nI`=jpOn&;vNOt;LMn#qmv1VyH;zeB7!^F)8{9Gx7pK|kr9a-=$DVI^>~0VGeUOq!{EsX-sb8Madsr` z%xHHclO{ipS&b|io6UyA z_U0_LJA81Czo{u))#hF^Uj*l|`BenxpyhWKxSoS{>Kri6Cv+z+wBIqAM7 zOmNNVT;7r0rIFZNG{tID0Q9bvuhtPcq5)#iG_ t^-r#tcMz_{X?`IhEcPs^hI?$X!|L5|RV-`d;cl6%v-u=k;@@UxE&wLw!y5nq delta 576 zcmezRo9W;mCe{X)sb>2&vfgLr!_NVVcmJP^KK(c3Z zd2WUOEU8Fj5ZqvytXE8{}jCCVVuc94o_k1 z%?^&sB;cI)k&29Pj%0KUE1Xl8a0$VQOjAK9YfJawhAX>XB!H0lP%Oy-ml3KtfslDz zn}^^;)i)qGj~nU`oUEoE1m}PA5(H;WYdt62Xp??DgiQ7XB+jCV+XUds5*KYo=#gC` zg3x2N*3uNNtme@#xXj}ECvf)Wj;BaYA9)hDuMBWy)ipI-ecn)2*FM3)umf Ch6g18 delta 843 zcmX@n&#`I(2TKFXRECW#+QOV1nFW<48Toleo6Uq-dBx$}DWw_O8B;Q3GjuZKyrU+6 zl#!U6q0ot>{D*?KJc2vf%i$@4x7o~bnFJE|aik(65|=wVh82mMmv9N0>z<~9thgxM zgBwZl!6E@<*&D@@97wW1s!t%x9{ntG7Ax0{zBbK6?$Igu>l z>DNP+b)100Et|Ma07w!x*2}Th(iBOt$D?0JvWq>RAn`T_JVkNx)o0(? zk+fcZhpc$=z7I!`Bs)L8VMgNCd=)}AcgEgK-Bke_j?NXCA`5>FaJV{zGuL zZ@$SmgAse`^!+pa;7vyL>8oxt@=gDClTma#kmZ1E_QyMnbCCH{?lDe7<{Lg>lwd-# hEZ`9%8!|uk31g@<`&3>IP}of0@Sm|@t0vQYb^t=oF~&pK<4WMwSMasp~ef)H1TO6;zgFz~VE?9H=(6|hd;;L9^rf$=H-)O&&qV35HcJ0(MKsx9M*$(FD9wm)QKWD*1bnn#Tw delta 386 zcmdnIl;!bK7M2E3-6|iznJuk!n29t09|G4!k<2^wDE(eyC diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree index 2ad10559c141617445da646821e3f2c915bd7ec3..3bde7b5217fd8f7a5065ff3214d2a036ac7aac62 100644 GIT binary patch delta 80 zcmbRKp0W2mBTECz)TWIr6WG|<3Mxx7^7A&&Wz%PbbFQ+xnZP+JHa8J6Y<7{%aG4B8 GeKP=wZ5!$U delta 90 zcmeBu&p7=(BTECz)Sitj6WBO8G7Bn8GV=3`HqU0$XGG#&WOp+`;>y|FM3(($8_A3$ J8|SER1^~RPraQO z;mQnrV-TFFenAM%2mg5p&h)@Z2#!(kA_V7d$T9?{C+rM@lNhlX!I6!6!wt7oD9xJ_ z&PmH(!3O7um!0H-b6z$GvBEhlZCVJ=nRoKCz-4@USrp-%sC69(OJA?&K!m}cjUikB DLqB(M delta 375 zcmZ4RgXzK#CYA=4sjeGYeC;_oG7Bn8GV=3`Hb>aIG9hu7IPPag;%2!nL6#NuK#{%e z?Zk+rSj9I6ncMCcgv@>5KM$GP8aN4=D;K;7nR`5B88Wvd>R1T%W_LZMeM_U0+V{Ya`rOW>+DuN41|kXb2-$kd3^Qb~&_QTyS^ylkS`MN3LbO$a=@ z9ok9-sn`2CmwToWp^W&M?Wj(#G&UslxV%*`@=!4 zw>}(Y9zbIR+P1iBgrqrS;#&bhbBU4~p_ffUnjj{S zv`c+Z#j6bO2Qx{N{b1m-v_Z(zllJ8kdqf;w2?gxkqi9CyaOOappMWs04PVNBJom_Y-J z#qRi-G{tQpj#7aABD_V};)w@F(9a;emLXD^@b|)FOxL|JdpWrTgk!UdO3KhqY*Im7 zh(#YR>x{!jrkvd=F}p@CfhAv6nx>gUgu9+U6_h z$|EGy;qW|i*>M}Ke9;`cuwPwNy-5v3Yvas}?J@ zqfRS&J?X~8hrDDqHPL9Kvr)pZ)+R}e51xPL+i(B-`d`=ezwh(tTkNJ=?X)FYLr#bG z_y(PIO4gw~Df2*}sdB?}EnxcQqF}&pr9G&2omgcJs=2~h12|XJ#elaAeyDyqKZRBk zmmC+sVNJb10R}gOARaZYL+oqZjOfx-h*;BX2hMU!dp#J(cYMYvwsu!rsjB>;XIdrG z_}y1J73D{LXq5A~8I3%jp2iuv`UhbK)48D;8`a5FVU9)o{K*Q2FwIP+qE*^dG{$)U zdpW9cKh{F#a?Q_YY9Bdwwo@gO?=O2TS&KD9H=&)Fv8E&7D2i>!9Hf?s{p%?i^??uy zgqA|Lk$li^O#~%DGRoEMR1S7QQM4HCqN3>|+J)>OGuSEK2~-Q^{RtFl3%oLg^597- zm$Ru3MwhQFH2zacChS09}8b$ko?lw$y7=7;u89~l^OIcVxK1xOQ zpr?JM64WQZ(QC~5#VmPaI17GL8Jss%a)!=eVL=vue}*}Z67j@iu#mFRigDjLD{cov z<%SIpz&z!)90~ryY{$EiL+v>oSuEsGWOm?8h(i=O@g(R|?nZ`Cc4LIE~*fp1^6`6WNI8pX}jI7de9m4Exja~Bc#4*w|V2c1t H&0dE;q0^Qi diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Zipper.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Zipper.doctree index 22f043b12d7b9f5b706b062996c883109708d36c..e51d16cd6e3747e1aba37b3fa906f2e12fbed1a2 100644 GIT binary patch delta 248 zcmbQ%%Jiv)iKT&MYWhZ&o1E-y1(hWk`FWe4an56fb9(u^;WCpIB@e?T-b&^(!#Sz4 zrW|n2V%2m;I7e7L5y7d|$VYI#YGxxincB$+&Q+aE1jk*kkqvIzMUzN`jImiALS~oE XPgS_GJxNGL8>CFT2PL`HDj3oI~GM^cV z8!c') @@ -162,7 +162,7 @@ The "down" and "up" refer to the movement of two of the top three items ``swap`` ~~~~~~~~ -.. code:: ipython2 +.. code:: python J('1 2 3 swap') @@ -175,7 +175,7 @@ The "down" and "up" refer to the movement of two of the top three items ``tuck`` ``over`` ~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('1 2 3 tuck') @@ -185,7 +185,7 @@ The "down" and "up" refer to the movement of two of the top three items 1 3 2 3 -.. code:: ipython2 +.. code:: python J('1 2 3 over') @@ -198,7 +198,7 @@ The "down" and "up" refer to the movement of two of the top three items ``unit`` ``quoted`` ``unquoted`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('1 2 3 unit') @@ -208,7 +208,7 @@ The "down" and "up" refer to the movement of two of the top three items 1 2 [3] -.. code:: ipython2 +.. code:: python J('1 2 3 quoted') @@ -218,7 +218,7 @@ The "down" and "up" refer to the movement of two of the top three items 1 [2] 3 -.. code:: ipython2 +.. code:: python J('1 [2] 3 unquoted') @@ -228,7 +228,7 @@ The "down" and "up" refer to the movement of two of the top three items 1 2 3 -.. code:: ipython2 +.. code:: python V('1 [dup] 3 unquoted') # Unquoting evaluates. Be aware. @@ -253,7 +253,7 @@ List words ``concat`` ``swoncat`` ``shunt`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3] [4 5 6] concat') @@ -263,7 +263,7 @@ List words [1 2 3 4 5 6] -.. code:: ipython2 +.. code:: python J('[1 2 3] [4 5 6] swoncat') @@ -273,7 +273,7 @@ List words [4 5 6 1 2 3] -.. code:: ipython2 +.. code:: python J('[1 2 3] [4 5 6] shunt') @@ -286,7 +286,7 @@ List words ``cons`` ``swons`` ``uncons`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('1 [2 3] cons') @@ -296,7 +296,7 @@ List words [1 2 3] -.. code:: ipython2 +.. code:: python J('[2 3] 1 swons') @@ -306,7 +306,7 @@ List words [1 2 3] -.. code:: ipython2 +.. code:: python J('[1 2 3] uncons') @@ -319,7 +319,7 @@ List words ``first`` ``second`` ``third`` ``rest`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3 4] first') @@ -329,7 +329,7 @@ List words 1 -.. code:: ipython2 +.. code:: python J('[1 2 3 4] second') @@ -339,7 +339,7 @@ List words 2 -.. code:: ipython2 +.. code:: python J('[1 2 3 4] third') @@ -349,7 +349,7 @@ List words 3 -.. code:: ipython2 +.. code:: python J('[1 2 3 4] rest') @@ -362,7 +362,7 @@ List words ``flatten`` ~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[[1] [2 [3] 4] [5 6]] flatten') @@ -377,7 +377,7 @@ List words ``at`` and ``getitem`` are the same function. ``of == swap at`` -.. code:: ipython2 +.. code:: python J('[10 11 12 13 14] 2 getitem') @@ -387,7 +387,7 @@ List words 12 -.. code:: ipython2 +.. code:: python J('[1 2 3 4] 0 at') @@ -397,7 +397,7 @@ List words 1 -.. code:: ipython2 +.. code:: python J('2 [1 2 3 4] of') @@ -407,7 +407,7 @@ List words 3 -.. code:: ipython2 +.. code:: python J('[1 2 3 4] 2 drop') @@ -417,7 +417,7 @@ List words [3 4] -.. code:: ipython2 +.. code:: python J('[1 2 3 4] 2 take') # reverses the order @@ -432,7 +432,7 @@ List words ``remove`` ~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3 1 4] 1 remove') @@ -445,7 +445,7 @@ List words ``reverse`` ~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3 4] reverse') @@ -458,7 +458,7 @@ List words ``size`` ~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 1 1 1] size') @@ -475,7 +475,7 @@ List words put the old stack on top of the new one. Think of it as a context switch. Niether of the lists/stacks change their order. -.. code:: ipython2 +.. code:: python J('1 2 3 [4 5 6] swaack') @@ -488,7 +488,7 @@ switch. Niether of the lists/stacks change their order. ``choice`` ``select`` ~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 9 1 choice') @@ -498,7 +498,7 @@ switch. Niether of the lists/stacks change their order. 9 -.. code:: ipython2 +.. code:: python J('23 9 0 choice') @@ -508,7 +508,7 @@ switch. Niether of the lists/stacks change their order. 23 -.. code:: ipython2 +.. code:: python J('[23 9 7] 1 select') # select is basically getitem, should retire it? @@ -518,7 +518,7 @@ switch. Niether of the lists/stacks change their order. 9 -.. code:: ipython2 +.. code:: python J('[23 9 7] 0 select') @@ -531,7 +531,7 @@ switch. Niether of the lists/stacks change their order. ``zip`` ~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3] [6 5 4] zip') @@ -541,7 +541,7 @@ switch. Niether of the lists/stacks change their order. [[6 1] [5 2] [4 3]] -.. code:: ipython2 +.. code:: python J('[1 2 3] [6 5 4] zip [sum] map') @@ -557,7 +557,7 @@ Math words ``+`` ``add`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 9 +') @@ -570,7 +570,7 @@ Math words ``-`` ``sub`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 9 -') @@ -583,7 +583,7 @@ Math words ``*`` ``mul`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 9 *') @@ -596,7 +596,7 @@ Math words ``/`` ``div`` ``floordiv`` ``truediv`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 9 /') @@ -606,7 +606,7 @@ Math words 2.5555555555555554 -.. code:: ipython2 +.. code:: python J('23 -9 truediv') @@ -616,7 +616,7 @@ Math words -2.5555555555555554 -.. code:: ipython2 +.. code:: python J('23 9 div') @@ -626,7 +626,7 @@ Math words 2 -.. code:: ipython2 +.. code:: python J('23 9 floordiv') @@ -636,7 +636,7 @@ Math words 2 -.. code:: ipython2 +.. code:: python J('23 -9 div') @@ -646,7 +646,7 @@ Math words -3 -.. code:: ipython2 +.. code:: python J('23 -9 floordiv') @@ -659,7 +659,7 @@ Math words ``%`` ``mod`` ``modulus`` ``rem`` ``remainder`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 9 %') @@ -672,7 +672,7 @@ Math words ``neg`` ~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 neg -5 neg') @@ -685,7 +685,7 @@ Math words ``pow`` ~~~~~~~ -.. code:: ipython2 +.. code:: python J('2 10 pow') @@ -698,7 +698,7 @@ Math words ``sqr`` ``sqrt`` ~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 sqr') @@ -708,7 +708,7 @@ Math words 529 -.. code:: ipython2 +.. code:: python J('23 sqrt') @@ -721,7 +721,7 @@ Math words ``++`` ``succ`` ``--`` ``pred`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('1 ++') @@ -731,7 +731,7 @@ Math words 2 -.. code:: ipython2 +.. code:: python J('1 --') @@ -744,7 +744,7 @@ Math words ``<<`` ``lshift`` ``>>`` ``rshift`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('8 1 <<') @@ -754,7 +754,7 @@ Math words 16 -.. code:: ipython2 +.. code:: python J('8 1 >>') @@ -767,7 +767,7 @@ Math words ``average`` ~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3 5] average') @@ -780,7 +780,7 @@ Math words ``range`` ``range_to_zero`` ``down_to_zero`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('5 range') @@ -790,7 +790,7 @@ Math words [4 3 2 1 0] -.. code:: ipython2 +.. code:: python J('5 range_to_zero') @@ -800,7 +800,7 @@ Math words [0 1 2 3 4 5] -.. code:: ipython2 +.. code:: python J('5 down_to_zero') @@ -813,7 +813,7 @@ Math words ``product`` ~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3 5] product') @@ -826,7 +826,7 @@ Math words ``sum`` ~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3 5] sum') @@ -839,7 +839,7 @@ Math words ``min`` ~~~~~~~ -.. code:: ipython2 +.. code:: python J('[1 2 3 5] min') @@ -852,7 +852,7 @@ Math words ``gcd`` ~~~~~~~ -.. code:: ipython2 +.. code:: python J('45 30 gcd') @@ -868,7 +868,7 @@ Math words If we represent fractions as a quoted pair of integers [q d] this word reduces them to their ... least common factors or whatever. -.. code:: ipython2 +.. code:: python J('[45 30] least_fraction') @@ -878,7 +878,7 @@ reduces them to their ... least common factors or whatever. [3 2] -.. code:: ipython2 +.. code:: python J('[23 12] least_fraction') @@ -896,7 +896,7 @@ Logic and Comparison Get the Boolean value of the item on the top of the stack. -.. code:: ipython2 +.. code:: python J('23 truthy') @@ -906,7 +906,7 @@ Get the Boolean value of the item on the top of the stack. True -.. code:: ipython2 +.. code:: python J('[] truthy') # Python semantics. @@ -916,7 +916,7 @@ Get the Boolean value of the item on the top of the stack. False -.. code:: ipython2 +.. code:: python J('0 truthy') @@ -930,7 +930,7 @@ Get the Boolean value of the item on the top of the stack. ? == dup truthy -.. code:: ipython2 +.. code:: python V('23 ?') @@ -944,7 +944,7 @@ Get the Boolean value of the item on the top of the stack. 23 True . -.. code:: ipython2 +.. code:: python J('[] ?') @@ -954,7 +954,7 @@ Get the Boolean value of the item on the top of the stack. [] False -.. code:: ipython2 +.. code:: python J('0 ?') @@ -967,7 +967,7 @@ Get the Boolean value of the item on the top of the stack. ``&`` ``and`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 9 &') @@ -980,7 +980,7 @@ Get the Boolean value of the item on the top of the stack. ``!=`` ``<>`` ``ne`` ~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('23 9 !=') @@ -996,7 +996,7 @@ Get the Boolean value of the item on the top of the stack. ``^`` ``xor`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('1 1 ^') @@ -1006,7 +1006,7 @@ Get the Boolean value of the item on the top of the stack. 0 -.. code:: ipython2 +.. code:: python J('1 0 ^') @@ -1022,7 +1022,7 @@ Miscellaneous ``help`` ~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[help] help') @@ -1036,7 +1036,7 @@ Miscellaneous ``parse`` ~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[parse] help') @@ -1047,7 +1047,7 @@ Miscellaneous -.. code:: ipython2 +.. code:: python J('1 "2 [3] dup" parse') @@ -1062,7 +1062,7 @@ Miscellaneous Evaluate a quoted Joy sequence. -.. code:: ipython2 +.. code:: python J('[1 2 dup + +] run') @@ -1078,7 +1078,7 @@ Combinators ``app1`` ``app2`` ``app3`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[app1] help') @@ -1095,7 +1095,7 @@ Combinators -.. code:: ipython2 +.. code:: python J('10 4 [sqr *] app1') @@ -1105,7 +1105,7 @@ Combinators 10 160 -.. code:: ipython2 +.. code:: python J('10 3 4 [sqr *] app2') @@ -1115,7 +1115,7 @@ Combinators 10 90 160 -.. code:: ipython2 +.. code:: python J('[app2] help') @@ -1131,7 +1131,7 @@ Combinators -.. code:: ipython2 +.. code:: python J('10 2 3 4 [sqr *] app3') @@ -1159,7 +1159,7 @@ Example, ``range``: range == [0 <=] [1 - dup] anamorphism -.. code:: ipython2 +.. code:: python J('3 [0 <=] [1 - dup] anamorphism') @@ -1172,7 +1172,7 @@ Example, ``range``: ``branch`` ~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('3 4 1 [+] [*] branch') @@ -1182,7 +1182,7 @@ Example, ``range``: 12 -.. code:: ipython2 +.. code:: python J('3 4 0 [+] [*] branch') @@ -1217,7 +1217,7 @@ in terms of ``app2``: cleave == [i] app2 [popd] dip -.. code:: ipython2 +.. code:: python J('10 2 [+] [-] cleave') @@ -1230,7 +1230,7 @@ in terms of ``app2``: ``dip`` ``dipd`` ``dipdd`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('1 2 3 4 5 [+] dip') @@ -1240,7 +1240,7 @@ in terms of ``app2``: 1 2 7 5 -.. code:: ipython2 +.. code:: python J('1 2 3 4 5 [+] dipd') @@ -1250,7 +1250,7 @@ in terms of ``app2``: 1 5 4 5 -.. code:: ipython2 +.. code:: python J('1 2 3 4 5 [+] dipdd') @@ -1270,7 +1270,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, n [Q] dupdip == n Q n -.. code:: ipython2 +.. code:: python V('23 [++] dupdip *') # N(N + 1) @@ -1289,7 +1289,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, ``genrec`` ``primrec`` ~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[genrec] help') @@ -1343,7 +1343,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, -.. code:: ipython2 +.. code:: python J('3 [1 <=] [] [dup --] [i *] genrec') @@ -1356,7 +1356,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, ``i`` ~~~~~ -.. code:: ipython2 +.. code:: python V('1 2 3 [+ +] i') @@ -1380,7 +1380,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, [predicate] [then] [else] ifte -.. code:: ipython2 +.. code:: python J('1 2 [1] [+] [*] ifte') @@ -1390,7 +1390,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, 3 -.. code:: ipython2 +.. code:: python J('1 2 [0] [+] [*] ifte') @@ -1403,7 +1403,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, ``infra`` ~~~~~~~~~ -.. code:: ipython2 +.. code:: python V('1 2 3 [4 5 6] [* +] infra') @@ -1426,7 +1426,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, ``loop`` ~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[loop] help') @@ -1445,7 +1445,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, -.. code:: ipython2 +.. code:: python V('3 dup [1 - dup] loop') @@ -1477,7 +1477,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, ``map`` ``pam`` ~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('10 [1 2 3] [*] map') @@ -1487,7 +1487,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, 10 [10 20 30] -.. code:: ipython2 +.. code:: python J('10 5 [[*][/][+][-]] pam') @@ -1503,7 +1503,7 @@ Expects a quoted program ``[Q]`` on the stack and some item under it, Run a quoted program enforcing `arity `__. -.. code:: ipython2 +.. code:: python J('1 2 3 4 5 [+] nullary') @@ -1513,7 +1513,7 @@ Run a quoted program enforcing 1 2 3 4 5 9 -.. code:: ipython2 +.. code:: python J('1 2 3 4 5 [+] unary') @@ -1523,7 +1523,7 @@ Run a quoted program enforcing 1 2 3 4 9 -.. code:: ipython2 +.. code:: python J('1 2 3 4 5 [+] binary') # + has arity 2 so this is technically pointless... @@ -1533,7 +1533,7 @@ Run a quoted program enforcing 1 2 3 9 -.. code:: ipython2 +.. code:: python J('1 2 3 4 5 [+] ternary') @@ -1546,7 +1546,7 @@ Run a quoted program enforcing ``step`` ~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[step] help') @@ -1574,7 +1574,7 @@ Run a quoted program enforcing -.. code:: ipython2 +.. code:: python V('0 [1 2 3] [+] step') @@ -1603,7 +1603,7 @@ Run a quoted program enforcing ``times`` ~~~~~~~~~ -.. code:: ipython2 +.. code:: python V('3 2 1 2 [+] times') @@ -1627,7 +1627,7 @@ Run a quoted program enforcing ``b`` ~~~~~ -.. code:: ipython2 +.. code:: python J('[b] help') @@ -1641,7 +1641,7 @@ Run a quoted program enforcing -.. code:: ipython2 +.. code:: python V('1 2 [3] [4] b') @@ -1665,7 +1665,7 @@ Run a quoted program enforcing [predicate] [body] while -.. code:: ipython2 +.. code:: python J('3 [0 >] [dup --] while') @@ -1678,7 +1678,7 @@ Run a quoted program enforcing ``x`` ~~~~~ -.. code:: ipython2 +.. code:: python J('[x] help') @@ -1693,7 +1693,7 @@ Run a quoted program enforcing -.. code:: ipython2 +.. code:: python V('1 [2] [i 3] x') # Kind of a pointless example. @@ -1720,7 +1720,7 @@ Implements `**Laws of Form** over quote-only datastructures (that is, datastructures that consist soley of containers, without strings or numbers or anything else.) -.. code:: ipython2 +.. code:: python J('[] void') @@ -1730,7 +1730,7 @@ soley of containers, without strings or numbers or anything else.) False -.. code:: ipython2 +.. code:: python J('[[]] void') @@ -1740,7 +1740,7 @@ soley of containers, without strings or numbers or anything else.) True -.. code:: ipython2 +.. code:: python J('[[][[]]] void') @@ -1750,7 +1750,7 @@ soley of containers, without strings or numbers or anything else.) True -.. code:: ipython2 +.. code:: python J('[[[]][[][]]] void') diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt index 29dc9fb..bbcbb73 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt @@ -76,7 +76,7 @@ E.g.: Implementation -------------- -.. code:: ipython2 +.. code:: python from functools import partial as curry from itertools import product @@ -86,7 +86,7 @@ Implementation The empty set and the set of just the empty string. -.. code:: ipython2 +.. code:: python phi = frozenset() # ϕ y = frozenset({''}) # λ @@ -101,7 +101,7 @@ alphabet with two symbols (if you had to.) I chose the names ``O`` and ``l`` (uppercase “o” and lowercase “L”) to look like ``0`` and ``1`` (zero and one) respectively. -.. code:: ipython2 +.. code:: python syms = O, l = frozenset({'0'}), frozenset({'1'}) @@ -123,7 +123,7 @@ expression* is one of: Where ``R`` and ``S`` stand for *regular expressions*. -.. code:: ipython2 +.. code:: python AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split() # Tags are just strings. @@ -133,7 +133,7 @@ only, these datastructures are immutable. String Representation of RE Datastructures ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python def stringy(re): ''' @@ -175,11 +175,11 @@ Match anything. Often spelled “.” I = (0|1)* -.. code:: ipython2 +.. code:: python I = (KSTAR, (OR, O, l)) -.. code:: ipython2 +.. code:: python print stringy(I) @@ -201,14 +201,14 @@ The example expression from Brzozowski: Note that it contains one of everything. -.. code:: ipython2 +.. code:: python a = (CONS, I, (CONS, l, (CONS, l, (CONS, l, I)))) b = (CONS, I, (CONS, O, l)) c = (CONS, l, (KSTAR, l)) it = (AND, a, (NOT, (OR, b, c))) -.. code:: ipython2 +.. code:: python print stringy(it) @@ -223,7 +223,7 @@ Note that it contains one of everything. Let’s get that auxiliary predicate function ``δ`` out of the way. -.. code:: ipython2 +.. code:: python def nully(R): ''' @@ -263,7 +263,7 @@ This is the straightforward version with no “compaction”. It works fine, but does waaaay too much work because the expressions grow each derivation. -.. code:: ipython2 +.. code:: python def D(symbol): @@ -308,7 +308,7 @@ derivation. Compaction Rules ~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python def _compaction_rule(relation, one, zero, a, b): return ( @@ -320,7 +320,7 @@ Compaction Rules An elegant symmetry. -.. code:: ipython2 +.. code:: python # R ∧ I = I ∧ R = R # R ∧ ϕ = ϕ ∧ R = ϕ @@ -341,7 +341,7 @@ We can save re-processing by remembering results we have already computed. RE datastructures are immutable and the ``derv()`` functions are *pure* so this is fine. -.. code:: ipython2 +.. code:: python class Memo(object): @@ -365,7 +365,7 @@ With “Compaction” This version uses the rules above to perform compaction. It keeps the expressions from growing too large. -.. code:: ipython2 +.. code:: python def D_compaction(symbol): @@ -414,7 +414,7 @@ Let’s try it out… (FIXME: redo.) -.. code:: ipython2 +.. code:: python o, z = D_compaction('0'), D_compaction('1') REs = set() @@ -605,20 +605,20 @@ You can see the one-way nature of the ``g`` state and the ``hij`` “trap” in the way that the ``.111.`` on the left-hand side of the ``&`` disappears once it has been matched. -.. code:: ipython2 +.. code:: python from collections import defaultdict from pprint import pprint from string import ascii_lowercase -.. code:: ipython2 +.. code:: python d0, d1 = D_compaction('0'), D_compaction('1') ``explore()`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python def explore(re): @@ -645,7 +645,7 @@ disappears once it has been matched. return table, accepting -.. code:: ipython2 +.. code:: python table, accepting = explore(it) table @@ -678,7 +678,7 @@ disappears once it has been matched. -.. code:: ipython2 +.. code:: python accepting @@ -697,7 +697,7 @@ Generate Diagram Once we have the FSM table and the set of accepting states we can generate the diagram above. -.. code:: ipython2 +.. code:: python _template = '''\ digraph finite_state_machine { @@ -722,7 +722,7 @@ generate the diagram above. ) ) -.. code:: ipython2 +.. code:: python print make_graph(table, accepting) @@ -776,7 +776,7 @@ Trampoline Function Python has no GOTO statement but we can fake it with a “trampoline” function. -.. code:: ipython2 +.. code:: python def trampoline(input_, jump_from, accepting): I = iter(input_) @@ -793,7 +793,7 @@ Stream Functions Little helpers to process the iterator of our data (a “stream” of “1” and “0” characters, not bits.) -.. code:: ipython2 +.. code:: python getch = lambda I: int(next(I)) @@ -816,7 +816,7 @@ code. (You have to imagine that these are GOTO statements in C or branches in assembly and that the state names are branch destination labels.) -.. code:: ipython2 +.. code:: python a = lambda I: c if getch(I) else b b = lambda I: _0(I) or d @@ -833,12 +833,12 @@ Note that the implementations of ``h`` and ``g`` are identical ergo ``h = g`` and we could eliminate one in the code but ``h`` is an accepting state and ``g`` isn’t. -.. code:: ipython2 +.. code:: python def acceptable(input_): return trampoline(input_, a, {h, i}) -.. code:: ipython2 +.. code:: python for n in range(2**5): s = bin(n)[2:] diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Developing.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Developing.rst.txt index 5b9314b..556225a 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Developing.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Developing.rst.txt @@ -12,7 +12,7 @@ As an example of developing a program in Joy let's take the first problem from t Find the sum of all the multiples of 3 or 5 below 1000. -.. code:: ipython2 +.. code:: python from notebook_preamble import J, V, define @@ -22,11 +22,11 @@ Sum a range filtered by a predicate Let's create a predicate that returns ``True`` if a number is a multiple of 3 or 5 and ``False`` otherwise. -.. code:: ipython2 +.. code:: python define('P == [3 % not] dupdip 5 % not or') -.. code:: ipython2 +.. code:: python V('80 P') @@ -108,11 +108,11 @@ the counter to the running sum. This function will do that: PE1.1 == + [+] dupdip -.. code:: ipython2 +.. code:: python define('PE1.1 == + [+] dupdip') -.. code:: ipython2 +.. code:: python V('0 0 3 PE1.1') @@ -131,7 +131,7 @@ the counter to the running sum. This function will do that: 3 3 . -.. code:: ipython2 +.. code:: python V('0 0 [3 2 1 3 1 2 3] [PE1.1] step') @@ -219,7 +219,7 @@ total to 60. How many multiples to sum? ^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. code:: ipython2 +.. code:: python 1000 / 15 @@ -232,7 +232,7 @@ How many multiples to sum? -.. code:: ipython2 +.. code:: python 66 * 15 @@ -245,7 +245,7 @@ How many multiples to sum? -.. code:: ipython2 +.. code:: python 1000 - 990 @@ -260,7 +260,7 @@ How many multiples to sum? We only want the terms *less than* 1000. -.. code:: ipython2 +.. code:: python 999 - 990 @@ -276,11 +276,11 @@ We only want the terms *less than* 1000. That means we want to run the full list of numbers sixty-six times to get to 990 and then the first four numbers 3 2 1 3 to get to 999. -.. code:: ipython2 +.. code:: python define('PE1 == 0 0 66 [[3 2 1 3 1 2 3] [PE1.1] step] times [3 2 1 3] [PE1.1] step pop') -.. code:: ipython2 +.. code:: python J('PE1') @@ -305,7 +305,7 @@ integer terms from the list. 3 2 1 3 1 2 3 0b 11 10 01 11 01 10 11 == 14811 -.. code:: ipython2 +.. code:: python 0b11100111011011 @@ -318,11 +318,11 @@ integer terms from the list. -.. code:: ipython2 +.. code:: python define('PE1.2 == [3 & PE1.1] dupdip 2 >>') -.. code:: ipython2 +.. code:: python V('0 0 14811 PE1.2') @@ -349,7 +349,7 @@ integer terms from the list. 3 3 3702 . -.. code:: ipython2 +.. code:: python V('3 3 3702 PE1.2') @@ -376,7 +376,7 @@ integer terms from the list. 8 5 925 . -.. code:: ipython2 +.. code:: python V('0 0 14811 7 [PE1.2] times pop') @@ -518,11 +518,11 @@ integer terms from the list. And so we have at last: -.. code:: ipython2 +.. code:: python define('PE1 == 0 0 66 [14811 7 [PE1.2] times pop] times 14811 4 [PE1.2] times popop') -.. code:: ipython2 +.. code:: python J('PE1') @@ -542,17 +542,17 @@ Let's refactor 14811 n [PE1.2] times pop n 14811 swap [PE1.2] times pop -.. code:: ipython2 +.. code:: python define('PE1.3 == 14811 swap [PE1.2] times pop') Now we can simplify the definition above: -.. code:: ipython2 +.. code:: python define('PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop') -.. code:: ipython2 +.. code:: python J('PE1') @@ -581,11 +581,11 @@ then four more. In the *Generator Programs* notebook we derive a generator that can be repeatedly driven by the ``x`` combinator to produce a stream of the seven numbers repeating over and over again. -.. code:: ipython2 +.. code:: python define('PE1.terms == [0 swap [dup [pop 14811] [] branch [3 &] dupdip 2 >>] dip rest cons]') -.. code:: ipython2 +.. code:: python J('PE1.terms 21 [x] times') @@ -598,7 +598,7 @@ produce a stream of the seven numbers repeating over and over again. We know from above that we need sixty-six times seven then four more terms to reach up to but not over one thousand. -.. code:: ipython2 +.. code:: python J('7 66 * 4 +') @@ -611,7 +611,7 @@ terms to reach up to but not over one thousand. Here they are... ~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('PE1.terms 466 [x] times pop') @@ -624,7 +624,7 @@ Here they are... ...and they do sum to 999. ~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[PE1.terms 466 [x] times pop] run sum') @@ -638,7 +638,7 @@ Now we can use ``PE1.1`` to accumulate the terms as we go, and then ``pop`` the generator and the counter from the stack when we're done, leaving just the sum. -.. code:: ipython2 +.. code:: python J('0 0 PE1.terms 466 [x [PE1.1] dip] times popop') @@ -654,7 +654,7 @@ A little further analysis renders iteration unnecessary. Consider finding the sum of the positive integers less than or equal to ten. -.. code:: ipython2 +.. code:: python J('[10 9 8 7 6 5 4 3 2 1] sum') @@ -686,11 +686,11 @@ positive integers is: (The formula also works for odd values of N, I'll leave that to you if you want to work it out or you can take my word for it.) -.. code:: ipython2 +.. code:: python define('F == dup ++ * 2 floordiv') -.. code:: ipython2 +.. code:: python V('10 F') @@ -727,7 +727,7 @@ And ending with: If we reverse one of these two blocks and sum pairs... -.. code:: ipython2 +.. code:: python J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip') @@ -737,7 +737,7 @@ If we reverse one of these two blocks and sum pairs... [[978 15] [980 12] [981 10] [984 9] [985 6] [987 5] [990 3]] -.. code:: ipython2 +.. code:: python J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map') @@ -750,7 +750,7 @@ If we reverse one of these two blocks and sum pairs... (Interesting that the sequence of seven numbers appears again in the rightmost digit of each term.) -.. code:: ipython2 +.. code:: python J('[ 3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map sum') @@ -771,7 +771,7 @@ additional unpaired terms between 990 and 1000: So we can give the "sum of all the multiples of 3 or 5 below 1000" like so: -.. code:: ipython2 +.. code:: python J('6945 33 * [993 995 996 999] cons sum') diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt index 55e1679..a59df18 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt @@ -3,7 +3,7 @@ Using ``x`` to Generate Values Cf. jp-reprod.html -.. code:: ipython2 +.. code:: python from notebook_preamble import J, V, define @@ -57,7 +57,7 @@ We can make a generator for the Natural numbers (0, 1, 2, …) by using Let’s try it: -.. code:: ipython2 +.. code:: python V('[0 swap [dup ++] dip rest cons] x') @@ -81,7 +81,7 @@ Let’s try it: After one application of ``x`` the quoted program contains ``1`` and ``0`` is below it on the stack. -.. code:: ipython2 +.. code:: python J('[0 swap [dup ++] dip rest cons] x x x x x pop') @@ -94,11 +94,11 @@ After one application of ``x`` the quoted program contains ``1`` and ``direco`` ---------- -.. code:: ipython2 +.. code:: python define('direco == dip rest cons') -.. code:: ipython2 +.. code:: python V('[0 swap [dup ++] direco] x') @@ -149,13 +149,13 @@ Reading from the bottom up: G == [direco] cons [swap] swap concat cons G == [direco] cons [swap] swoncat cons -.. code:: ipython2 +.. code:: python define('G == [direco] cons [swap] swoncat cons') Let’s try it out: -.. code:: ipython2 +.. code:: python J('0 [dup ++] G') @@ -165,7 +165,7 @@ Let’s try it out: [0 swap [dup ++] direco] -.. code:: ipython2 +.. code:: python J('0 [dup ++] G x x x pop') @@ -178,7 +178,7 @@ Let’s try it out: Powers of 2 ~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python J('1 [dup 1 <<] G x x x x x x x x x pop') @@ -194,7 +194,7 @@ Powers of 2 If we have one of these quoted programs we can drive it using ``times`` with the ``x`` combinator. -.. code:: ipython2 +.. code:: python J('23 [dup ++] G 5 [x] times') @@ -226,11 +226,11 @@ int: And pick them off by masking with 3 (binary 11) and then shifting the int right two bits. -.. code:: ipython2 +.. code:: python define('PE1.1 == dup [3 &] dip 2 >>') -.. code:: ipython2 +.. code:: python V('14811 PE1.1') @@ -252,7 +252,7 @@ int right two bits. If we plug ``14811`` and ``[PE1.1]`` into our generator form… -.. code:: ipython2 +.. code:: python J('14811 [PE1.1] G') @@ -264,7 +264,7 @@ If we plug ``14811`` and ``[PE1.1]`` into our generator form… …we get a generator that works for seven cycles before it reaches zero: -.. code:: ipython2 +.. code:: python J('[14811 swap [PE1.1] direco] 7 [x] times') @@ -280,11 +280,11 @@ Reset at Zero We need a function that checks if the int has reached zero and resets it if so. -.. code:: ipython2 +.. code:: python define('PE1.1.check == dup [pop 14811] [] branch') -.. code:: ipython2 +.. code:: python J('14811 [PE1.1.check PE1.1] G') @@ -294,7 +294,7 @@ if so. [14811 swap [PE1.1.check PE1.1] direco] -.. code:: ipython2 +.. code:: python J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times') @@ -316,7 +316,7 @@ In the PE1 problem we are asked to sum all the multiples of three and five less than 1000. It’s worked out that we need to use all seven numbers sixty-six times and then four more. -.. code:: ipython2 +.. code:: python J('7 66 * 4 +') @@ -328,7 +328,7 @@ numbers sixty-six times and then four more. If we drive our generator 466 times and sum the stack we get 999. -.. code:: ipython2 +.. code:: python J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times') @@ -338,7 +338,7 @@ If we drive our generator 466 times and sum the stack we get 999. 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 [57 swap [PE1.1.check PE1.1] direco] -.. code:: ipython2 +.. code:: python J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum') @@ -351,13 +351,13 @@ If we drive our generator 466 times and sum the stack we get 999. Project Euler Problem One ------------------------- -.. code:: ipython2 +.. code:: python define('PE1.2 == + dup [+] dip') Now we can add ``PE1.2`` to the quoted program given to ``G``. -.. code:: ipython2 +.. code:: python J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop') @@ -445,15 +445,15 @@ Putting it all together: F == + [popdd over] cons infra uncons fib_gen == [1 1 F] -.. code:: ipython2 +.. code:: python define('fib == + [popdd over] cons infra uncons') -.. code:: ipython2 +.. code:: python define('fib_gen == [1 1 fib]') -.. code:: ipython2 +.. code:: python J('fib_gen 10 [x] times') @@ -473,14 +473,14 @@ Now that we have a generator for the Fibonacci sequence, we need a function that adds a term in the sequence to a sum if it is even, and ``pop``\ s it otherwise. -.. code:: ipython2 +.. code:: python define('PE2.1 == dup 2 % [+] [pop] branch') And a predicate function that detects when the terms in the series “exceed four million”. -.. code:: ipython2 +.. code:: python define('>4M == 4000000 >') @@ -488,11 +488,11 @@ Now it’s straightforward to define ``PE2`` as a recursive function that generates terms in the Fibonacci sequence until they exceed four million and sums the even ones. -.. code:: ipython2 +.. code:: python define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec') -.. code:: ipython2 +.. code:: python J('PE2') @@ -535,7 +535,7 @@ So the Fibonacci sequence considered in terms of just parity would be: Every third term is even. -.. code:: ipython2 +.. code:: python J('[1 0 fib] x x x') # To start the sequence with 1 1 2 3 instead of 1 2 3. @@ -547,7 +547,7 @@ Every third term is even. Drive the generator three times and ``popop`` the two odd terms. -.. code:: ipython2 +.. code:: python J('[1 0 fib] x x x [popop] dipd') @@ -557,11 +557,11 @@ Drive the generator three times and ``popop`` the two odd terms. 2 [3 2 fib] -.. code:: ipython2 +.. code:: python define('PE2.2 == x x x [popop] dipd') -.. code:: ipython2 +.. code:: python J('[1 0 fib] 10 [PE2.2] times') @@ -574,7 +574,7 @@ Drive the generator three times and ``popop`` the two odd terms. Replace ``x`` with our new driver function ``PE2.2`` and start our ``fib`` generator at ``1 0``. -.. code:: ipython2 +.. code:: python J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec') @@ -593,11 +593,11 @@ modifications to the default ``x``? An Interesting Variation ------------------------ -.. code:: ipython2 +.. code:: python define('codireco == cons dip rest cons') -.. code:: ipython2 +.. code:: python V('[0 [dup ++] codireco] x') @@ -620,11 +620,11 @@ An Interesting Variation 0 [1 [dup ++] codireco] . -.. code:: ipython2 +.. code:: python define('G == [codireco] cons cons') -.. code:: ipython2 +.. code:: python J('230 [dup ++] G 5 [x] times pop') diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Intro.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Intro.rst.txt index b832048..73704cf 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Intro.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Intro.rst.txt @@ -150,7 +150,7 @@ TBD (look in the :module: joy.parser module.) Examples ~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python joy.parser.text_to_expression('1 2 3 4 5') # A simple sequence. @@ -160,7 +160,7 @@ Examples (1, (2, (3, (4, (5, ()))))) -.. code:: ipython2 +.. code:: python joy.parser.text_to_expression('[1 2 3] 4 5') # Three items, the first is a list with three items @@ -170,7 +170,7 @@ Examples ((1, (2, (3, ()))), (4, (5, ()))) -.. code:: ipython2 +.. code:: python joy.parser.text_to_expression('1 23 ["four" [-5.0] cons] 8888') # A mixed bag. cons is # a Symbol, no lookup at @@ -184,7 +184,7 @@ Examples -.. code:: ipython2 +.. code:: python joy.parser.text_to_expression('[][][][][]') # Five empty lists. @@ -197,7 +197,7 @@ Examples -.. code:: ipython2 +.. code:: python joy.parser.text_to_expression('[[[[[]]]]]') # Five nested lists. @@ -221,7 +221,7 @@ provide control-flow and higher-order operations. Many of the functions are defined in Python, like ``dip``: -.. code:: ipython2 +.. code:: python print inspect.getsource(joy.library.dip) @@ -239,7 +239,7 @@ When the interpreter executes a definition function that function just pushes its body expression onto the pending expression (the continuation) and returns control to the interpreter. -.. code:: ipython2 +.. code:: python print joy.library.definitions diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt index 569d665..a625ac3 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt @@ -36,7 +36,7 @@ implementation under the hood. (Where does the “type” come from? It has a contingent existence predicated on the disciplined use of these functions on otherwise undistinguished Joy datastructures.) -.. code:: ipython2 +.. code:: python from notebook_preamble import D, J, V, define, DefinitionWrapper @@ -87,11 +87,11 @@ Definition: Tree-new == swap [[] []] cons cons -.. code:: ipython2 +.. code:: python define('Tree-new == swap [[] []] cons cons') -.. code:: ipython2 +.. code:: python J('"v" "k" Tree-new') @@ -163,11 +163,11 @@ comparison operator: P < == pop roll> pop first < P == pop roll> pop first -.. code:: ipython2 +.. code:: python define('P == pop roll> pop first') -.. code:: ipython2 +.. code:: python J('["old_key" 23 [] []] 17 "new_key" ["..."] P') @@ -242,11 +242,11 @@ And so ``T`` is just: T == cons cons [dipdd] cons infra -.. code:: ipython2 +.. code:: python define('T == cons cons [dipdd] cons infra') -.. code:: ipython2 +.. code:: python J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T') @@ -266,7 +266,7 @@ This is very very similar to the above: [key_n value_n left right] value key [Tree-add] E [key_n value_n left right] value key [Tree-add] [P <] [Te] [Ee] ifte -.. code:: ipython2 +.. code:: python define('E == [P <] [Te] [Ee] ifte') @@ -278,11 +278,11 @@ instead of the right, so the only difference is that it must use Te == cons cons [dipd] cons infra -.. code:: ipython2 +.. code:: python define('Te == cons cons [dipd] cons infra') -.. code:: ipython2 +.. code:: python J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te') @@ -320,11 +320,11 @@ Example: key new_value [ left right] cons cons [key new_value left right] -.. code:: ipython2 +.. code:: python define('Ee == pop swap roll< rest rest cons cons') -.. code:: ipython2 +.. code:: python J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee') @@ -355,14 +355,14 @@ Putting it all together: Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec -.. code:: ipython2 +.. code:: python define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec') Examples ~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[] 23 "b" Tree-add') # Initial @@ -372,7 +372,7 @@ Examples ['b' 23 [] []] -.. code:: ipython2 +.. code:: python J('["b" 23 [] []] 88 "c" Tree-add') # Greater than @@ -382,7 +382,7 @@ Examples ['b' 23 [] ['c' 88 [] []]] -.. code:: ipython2 +.. code:: python J('["b" 23 [] []] 88 "a" Tree-add') # Less than @@ -392,7 +392,7 @@ Examples ['b' 23 ['a' 88 [] []] []] -.. code:: ipython2 +.. code:: python J('["b" 23 [] []] 88 "b" Tree-add') # Equal to @@ -402,7 +402,7 @@ Examples ['b' 88 [] []] -.. code:: ipython2 +.. code:: python J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Series. @@ -412,7 +412,7 @@ Examples ['b' 23 ['a' 88 [] []] ['c' 44 [] []]] -.. code:: ipython2 +.. code:: python J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step') @@ -444,7 +444,7 @@ values: ------------------------- a < b L -.. code:: ipython2 +.. code:: python J("1 0 ['G'] ['E'] ['L'] cmp") @@ -454,7 +454,7 @@ values: 'G' -.. code:: ipython2 +.. code:: python J("1 1 ['G'] ['E'] ['L'] cmp") @@ -464,7 +464,7 @@ values: 'E' -.. code:: ipython2 +.. code:: python J("0 1 ['G'] ['E'] ['L'] cmp") @@ -514,7 +514,7 @@ Or just: P == over [popop popop first] nullary -.. code:: ipython2 +.. code:: python define('P == over [popop popop first] nullary') @@ -541,11 +541,11 @@ to understand: Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec -.. code:: ipython2 +.. code:: python define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec') -.. code:: ipython2 +.. code:: python J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Still works. @@ -685,14 +685,14 @@ Working backward: Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec -.. code:: ipython2 +.. code:: python define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec') Examples ~~~~~~~~ -.. code:: ipython2 +.. code:: python J('[] [foo] Tree-iter') # It doesn't matter what F is as it won't be used. @@ -702,7 +702,7 @@ Examples -.. code:: ipython2 +.. code:: python J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter") @@ -712,7 +712,7 @@ Examples 'b' 'a' 'c' -.. code:: ipython2 +.. code:: python J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter") @@ -731,7 +731,7 @@ to it will only occur once within it, and we can query it in `:math:`O(\log_2 N)` `__ time. -.. code:: ipython2 +.. code:: python J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step') @@ -741,11 +741,11 @@ time. [3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]] -.. code:: ipython2 +.. code:: python define('to_set == [] swap [0 swap Tree-add] step') -.. code:: ipython2 +.. code:: python J('[3 9 5 2 8 6 7 8 4] to_set') @@ -758,11 +758,11 @@ time. And with that we can write a little program ``unique`` to remove duplicate items from a list. -.. code:: ipython2 +.. code:: python define('unique == [to_set [first] Tree-iter] cons run') -.. code:: ipython2 +.. code:: python J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique') # Filter duplicate items. @@ -872,7 +872,7 @@ Let’s do a little semantic factoring: Now we can sort sequences. -.. code:: ipython2 +.. code:: python #define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec') @@ -892,7 +892,7 @@ Now we can sort sequences. -.. code:: ipython2 +.. code:: python J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order') @@ -1070,7 +1070,7 @@ So: Tree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec -.. code:: ipython2 +.. code:: python # I don't want to deal with name conflicts with the above so I'm inlining everything here. # The original Joy system has "hide" which is a meta-command which allows you to use named @@ -1088,7 +1088,7 @@ So: ] genrec ''') -.. code:: ipython2 +.. code:: python J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get') @@ -1098,7 +1098,7 @@ So: 'mike not in tree' -.. code:: ipython2 +.. code:: python J('["gary" 23 [] []] "gary" [popop "err"] Tree-get') @@ -1108,7 +1108,7 @@ So: 23 -.. code:: ipython2 +.. code:: python J(''' @@ -1124,7 +1124,7 @@ So: 2 -.. code:: ipython2 +.. code:: python J(''' @@ -1500,7 +1500,7 @@ Refactoring By the standards of the code I’ve written so far, this is a *huge* Joy program. -.. code:: ipython2 +.. code:: python DefinitionWrapper.add_definitions(''' first_two == uncons uncons pop @@ -1519,7 +1519,7 @@ program. Tree-Delete == [pop not] [pop] [R0] [R1] genrec ''', D) -.. code:: ipython2 +.. code:: python J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ") @@ -1529,7 +1529,7 @@ program. ['a' 23 [] ['b' 88 [] []]] -.. code:: ipython2 +.. code:: python J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ") @@ -1539,7 +1539,7 @@ program. ['a' 23 [] ['c' 44 [] []]] -.. code:: ipython2 +.. code:: python J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ") @@ -1549,7 +1549,7 @@ program. ['b' 88 [] ['c' 44 [] []]] -.. code:: ipython2 +.. code:: python J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ") @@ -1559,7 +1559,7 @@ program. ['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] -.. code:: ipython2 +.. code:: python J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step') @@ -1569,7 +1569,7 @@ program. [4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] -.. code:: ipython2 +.. code:: python J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ") @@ -1579,7 +1579,7 @@ program. [4 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]] -.. code:: ipython2 +.. code:: python J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ") diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt index 3262e84..5afb8e2 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt @@ -1,4 +1,4 @@ -.. code:: ipython2 +.. code:: python from notebook_preamble import J, V, define @@ -81,13 +81,13 @@ the variables: The three arguments are to the left, so we can “chop off” everything to the right and say it’s the definition of the ``quadratic`` function: -.. code:: ipython2 +.. code:: python define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2') Let’s try it out: -.. code:: ipython2 +.. code:: python J('3 1 1 quadratic') @@ -102,7 +102,7 @@ lines are the ``dip`` and ``dipd`` combinators building the main program by incorporating the values on the stack. Then that program runs and you get the results. This is pretty typical of Joy code. -.. code:: ipython2 +.. code:: python V('-5 1 4 quadratic') diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt index 9159882..65c4480 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt @@ -1,4 +1,4 @@ -.. code:: ipython2 +.. code:: python from notebook_preamble import D, DefinitionWrapper, J, V, define @@ -80,7 +80,7 @@ is a recursive function ``H :: A -> C`` that converts a value of type It may be helpful to see this function implemented in imperative Python code. -.. code:: ipython2 +.. code:: python def hylomorphism(c, F, P, G): '''Return a hylomorphism function H.''' @@ -185,7 +185,7 @@ the left so we have a definition for ``hylomorphism``: hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec -.. code:: ipython2 +.. code:: python define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec') @@ -203,13 +203,13 @@ To sum a range of integers from 0 to *n* - 1: - ``[G]`` is ``[-- dup]`` - ``[F]`` is ``[+]`` -.. code:: ipython2 +.. code:: python define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism') Let’s try it: -.. code:: ipython2 +.. code:: python J('5 triangular_number') @@ -219,7 +219,7 @@ Let’s try it: 10 -.. code:: ipython2 +.. code:: python J('[0 1 2 3 4 5 6] [triangular_number] map') @@ -405,11 +405,11 @@ Each of the above variations can be used to make four slightly different H1 == [P] [pop c] [G] [dip F] genrec == [0 <=] [pop []] [-- dup] [dip swons] genrec -.. code:: ipython2 +.. code:: python define('range == [0 <=] [] [-- dup] [swons] hylomorphism') -.. code:: ipython2 +.. code:: python J('5 range') @@ -427,11 +427,11 @@ Each of the above variations can be used to make four slightly different H2 == c swap [P] [pop] [G [F] dip] primrec == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec -.. code:: ipython2 +.. code:: python define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec') -.. code:: ipython2 +.. code:: python J('5 range_reverse') @@ -449,11 +449,11 @@ Each of the above variations can be used to make four slightly different H3 == [P] [pop c] [[G] dupdip] [dip F] genrec == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec -.. code:: ipython2 +.. code:: python define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec') -.. code:: ipython2 +.. code:: python J('5 ranger') @@ -471,11 +471,11 @@ Each of the above variations can be used to make four slightly different H4 == c swap [P] [pop] [[F] dupdip G ] primrec == [] swap [0 <=] [pop] [[swons] dupdip --] primrec -.. code:: ipython2 +.. code:: python define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec') -.. code:: ipython2 +.. code:: python J('5 ranger_reverse') @@ -501,7 +501,7 @@ and makes some new value. C == [not] c [uncons swap] [F] hylomorphism -.. code:: ipython2 +.. code:: python define('swuncons == uncons swap') # Awkward name. @@ -511,11 +511,11 @@ An example of a catamorphism is the sum function. sum == [not] 0 [swuncons] [+] hylomorphism -.. code:: ipython2 +.. code:: python define('sum == [not] 0 [swuncons] [+] hylomorphism') -.. code:: ipython2 +.. code:: python J('[5 4 3 2 1] sum') @@ -531,7 +531,7 @@ The ``step`` combinator The ``step`` combinator will usually be better to use than ``catamorphism``. -.. code:: ipython2 +.. code:: python J('[step] help') @@ -560,11 +560,11 @@ The ``step`` combinator will usually be better to use than -.. code:: ipython2 +.. code:: python define('sum == 0 swap [+] step') -.. code:: ipython2 +.. code:: python J('[5 4 3 2 1] sum') @@ -592,11 +592,11 @@ With: G == -- P == 1 <= -.. code:: ipython2 +.. code:: python define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec') -.. code:: ipython2 +.. code:: python J('5 factorial') @@ -635,11 +635,11 @@ We would use: G == rest dup P == not -.. code:: ipython2 +.. code:: python define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec') -.. code:: ipython2 +.. code:: python J('[1 2 3] tails') diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt index 0f90445..02ecb3b 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt @@ -9,14 +9,14 @@ dictionary. However, there’s no function that does that. Adding a new function to the dictionary is a meta-interpreter action, you have to do it in Python, not Joy. -.. code:: ipython2 +.. code:: python from notebook_preamble import D, J, V A long trace ------------ -.. code:: ipython2 +.. code:: python V('[23 18] average') @@ -81,7 +81,7 @@ An efficient ``sum`` function is already in the library. But for ``size`` we can use a “compiled” version hand-written in Python to speed up evaluation and make the trace more readable. -.. code:: ipython2 +.. code:: python from joy.library import SimpleFunctionWrapper from joy.utils.stack import iter_stack @@ -99,7 +99,7 @@ up evaluation and make the trace more readable. Now we replace the old version in the dictionary with the new version, and re-evaluate the expression. -.. code:: ipython2 +.. code:: python D['size'] = size @@ -108,7 +108,7 @@ A shorter trace You can see that ``size`` now executes in a single step. -.. code:: ipython2 +.. code:: python V('[23 18] average') diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt index 6b9081f..7f273d8 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt @@ -148,11 +148,11 @@ Working backwards: Define ``treestep`` ------------------- -.. code:: ipython2 +.. code:: python from notebook_preamble import D, J, V, define, DefinitionWrapper -.. code:: ipython2 +.. code:: python DefinitionWrapper.add_definitions(''' @@ -173,7 +173,7 @@ all nodes in a tree with this function: sumtree == [pop 0] [] [sum +] treestep -.. code:: ipython2 +.. code:: python define('sumtree == [pop 0] [] [sum +] treestep') @@ -185,7 +185,7 @@ Running this function on an empty tree value gives zero: ------------------------------------ 0 -.. code:: ipython2 +.. code:: python J('[] sumtree') # Empty tree. @@ -205,7 +205,7 @@ Running it on a non-empty node: n m + n+m -.. code:: ipython2 +.. code:: python J('[23] sumtree') # No child trees. @@ -215,7 +215,7 @@ Running it on a non-empty node: 23 -.. code:: ipython2 +.. code:: python J('[23 []] sumtree') # Child tree, empty. @@ -225,7 +225,7 @@ Running it on a non-empty node: 23 -.. code:: ipython2 +.. code:: python J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees. @@ -235,7 +235,7 @@ Running it on a non-empty node: 32 -.. code:: ipython2 +.. code:: python J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc... @@ -245,7 +245,7 @@ Running it on a non-empty node: 49 -.. code:: ipython2 +.. code:: python J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate "spelling". @@ -255,7 +255,7 @@ Running it on a non-empty node: 49 -.. code:: ipython2 +.. code:: python J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep') # Replace each node. @@ -265,7 +265,7 @@ Running it on a non-empty node: [23 [23 [23] [23]] [23] [23 []]] -.. code:: ipython2 +.. code:: python J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep') @@ -275,7 +275,7 @@ Running it on a non-empty node: [1 [1 [1] [1]] [1] [1 []]] -.. code:: ipython2 +.. code:: python J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree') @@ -285,7 +285,7 @@ Running it on a non-empty node: 6 -.. code:: ipython2 +.. code:: python J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function. @@ -295,7 +295,7 @@ Running it on a non-empty node: 6 -.. code:: ipython2 +.. code:: python J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function. @@ -339,7 +339,7 @@ Traversal This doesn’t quite work: -.. code:: ipython2 +.. code:: python J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep') @@ -369,7 +369,7 @@ So: [] [first] [flatten cons] treestep -.. code:: ipython2 +.. code:: python J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first] [flatten cons] treestep') @@ -401,7 +401,7 @@ So: [] [i roll< swons concat] [first] treestep -.. code:: ipython2 +.. code:: python J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [uncons pop] [i roll< swons concat] treestep') @@ -429,7 +429,7 @@ Plugging in our BTree structure: [key value] N [left right] [K] C -.. code:: ipython2 +.. code:: python J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind') @@ -444,7 +444,7 @@ Plugging in our BTree structure: Iteration through the nodes -.. code:: ipython2 +.. code:: python J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] ["N"] [step] treegrind') @@ -456,7 +456,7 @@ Iteration through the nodes Sum the nodes’ keys. -.. code:: ipython2 +.. code:: python J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind') @@ -468,7 +468,7 @@ Sum the nodes’ keys. Rebuild the tree using ``map`` (imitating ``treestep``.) -.. code:: ipython2 +.. code:: python J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind') @@ -574,7 +574,7 @@ Putting it together To me, that seems simpler than the ``genrec`` version. -.. code:: ipython2 +.. code:: python DefinitionWrapper.add_definitions(''' @@ -587,7 +587,7 @@ To me, that seems simpler than the ``genrec`` version. ''', D) -.. code:: ipython2 +.. code:: python J('''\ @@ -603,7 +603,7 @@ To me, that seems simpler than the ``genrec`` version. 15 -.. code:: ipython2 +.. code:: python J('''\ diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt index cd85c67..4e70a1a 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt @@ -1,7 +1,7 @@ Type Checking ============= -.. code:: ipython2 +.. code:: python import logging, sys @@ -11,7 +11,7 @@ Type Checking level=logging.INFO, ) -.. code:: ipython2 +.. code:: python from joy.utils.types import ( doc_from_stack_effect, @@ -22,7 +22,7 @@ Type Checking JoyTypeError, ) -.. code:: ipython2 +.. code:: python D = FUNCTIONS.copy() del D['product'] @@ -31,7 +31,7 @@ Type Checking An Example ---------- -.. code:: ipython2 +.. code:: python fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0] @@ -46,7 +46,7 @@ An Example 40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘ -.. code:: ipython2 +.. code:: python print doc_from_stack_effect(fi, fo) @@ -56,13 +56,13 @@ An Example ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) -.. code:: ipython2 +.. code:: python from joy.parser import text_to_expression from joy.utils.stack import stack_to_string -.. code:: ipython2 +.. code:: python e = text_to_expression('0 1 2 [3 4]') # reverse order print stack_to_string(e) @@ -73,7 +73,7 @@ An Example [3 4] 2 1 0 -.. code:: ipython2 +.. code:: python u = unify(e, fi)[0] u @@ -87,7 +87,7 @@ An Example -.. code:: ipython2 +.. code:: python g = reify(u, (fi, fo)) print doc_from_stack_effect(*g) @@ -101,11 +101,11 @@ An Example Unification Works “in Reverse” ------------------------------ -.. code:: ipython2 +.. code:: python e = text_to_expression('[2 3]') -.. code:: ipython2 +.. code:: python u = unify(e, fo)[0] # output side, not input side u @@ -119,7 +119,7 @@ Unification Works “in Reverse” -.. code:: ipython2 +.. code:: python g = reify(u, (fi, fo)) print doc_from_stack_effect(*g) @@ -133,7 +133,7 @@ Unification Works “in Reverse” Failing a Check --------------- -.. code:: ipython2 +.. code:: python fi, fo = infer(dup, mul)[0] @@ -146,7 +146,7 @@ Failing a Check 31 (i1 -- i2) ∘ -.. code:: ipython2 +.. code:: python e = text_to_expression('"two"') print stack_to_string(e) @@ -157,7 +157,7 @@ Failing a Check 'two' -.. code:: ipython2 +.. code:: python try: unify(e, fi) diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt index 4c91600..8ca737d 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt @@ -184,7 +184,7 @@ Compiling ``pop∘swap∘roll<`` The simplest way to “compile” this function would be something like: -.. code:: ipython2 +.. code:: python def poswrd(s, e, d): return rolldown(*swap(*pop(s, e, d))) @@ -200,7 +200,7 @@ Looking ahead for a moment, from the stack effect comment: We should be able to directly write out a Python function like: -.. code:: ipython2 +.. code:: python def poswrd(stack): (_, (a, (b, (c, stack)))) = stack @@ -393,7 +393,7 @@ And there you have it, the stack effect for From this stack effect comment it should be possible to construct the following Python code: -.. code:: ipython2 +.. code:: python def F(stack): (_, (d, (c, ((a, (b, S0)), stack)))) = stack @@ -408,7 +408,7 @@ Representing Stack Effect Comments in Python I’m going to use pairs of tuples of type descriptors, which will be integers or tuples of type descriptors: -.. code:: ipython2 +.. code:: python roll_dn = (1, 2, 3), (2, 3, 1) @@ -419,7 +419,7 @@ integers or tuples of type descriptors: ``compose()`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python def compose(f, g): @@ -465,7 +465,7 @@ integers or tuples of type descriptors: ``unify()`` ~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python def unify(u, v, s=None): if s is None: @@ -483,7 +483,7 @@ integers or tuples of type descriptors: ``update()`` ~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python def update(s, term): if not isinstance(term, tuple): @@ -493,7 +493,7 @@ integers or tuples of type descriptors: ``relabel()`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python def relabel(left, right): return left, _1000(right) @@ -517,7 +517,7 @@ integers or tuples of type descriptors: ``delabel()`` ~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python def delabel(f): s = {u: i for i, u in enumerate(sorted(_unique(f)))} @@ -551,7 +551,7 @@ At last we put it all together in a function ``C()`` that accepts two stack effect comments and returns their composition (or raises and exception if they can’t be composed due to type conflicts.) -.. code:: ipython2 +.. code:: python def C(f, g): f, g = relabel(f, g) @@ -560,7 +560,7 @@ exception if they can’t be composed due to type conflicts.) Let’s try it out. -.. code:: ipython2 +.. code:: python C(pop, swap) @@ -573,7 +573,7 @@ Let’s try it out. -.. code:: ipython2 +.. code:: python C(C(pop, swap), roll_dn) @@ -586,7 +586,7 @@ Let’s try it out. -.. code:: ipython2 +.. code:: python C(swap, roll_dn) @@ -599,7 +599,7 @@ Let’s try it out. -.. code:: ipython2 +.. code:: python C(pop, C(swap, roll_dn)) @@ -612,7 +612,7 @@ Let’s try it out. -.. code:: ipython2 +.. code:: python poswrd = reduce(C, (pop, swap, roll_dn)) poswrd @@ -633,13 +633,13 @@ Here’s that trick to represent functions like ``rest`` and ``cons`` that manipulate stacks. We use a cons-list of tuples and give the tails their own numbers. Then everything above already works. -.. code:: ipython2 +.. code:: python rest = ((1, 2),), (2,) cons = (1, 2), ((1, 2),) -.. code:: ipython2 +.. code:: python C(poswrd, rest) @@ -671,7 +671,7 @@ The translation table, if you will, would be: 0: 0, } -.. code:: ipython2 +.. code:: python F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons)) @@ -699,11 +699,11 @@ Dealing with ``cons`` and ``uncons`` However, if we try to compose e.g. ``cons`` and ``uncons`` it won’t work: -.. code:: ipython2 +.. code:: python uncons = ((1, 2),), (1, 2) -.. code:: ipython2 +.. code:: python try: C(cons, uncons) @@ -723,7 +723,7 @@ The problem is that the ``unify()`` function as written doesn’t handle the case when both terms are tuples. We just have to add a clause to deal with this recursively: -.. code:: ipython2 +.. code:: python def unify(u, v, s=None): if s is None: @@ -753,7 +753,7 @@ deal with this recursively: return s -.. code:: ipython2 +.. code:: python C(cons, uncons) @@ -771,7 +771,7 @@ Part III: Compiling Yin Functions Now consider the Python function we would like to derive: -.. code:: ipython2 +.. code:: python def F_python(stack): (_, (d, (c, ((a, (b, S0)), stack)))) = stack @@ -779,7 +779,7 @@ Now consider the Python function we would like to derive: And compare it to the input stack effect comment tuple we just computed: -.. code:: ipython2 +.. code:: python F[0] @@ -816,7 +816,7 @@ Eh? And the return tuple -.. code:: ipython2 +.. code:: python F[1] @@ -848,7 +848,7 @@ Python Identifiers We want to substitute Python identifiers for the integers. I’m going to repurpose ``joy.parser.Symbol`` class for this: -.. code:: ipython2 +.. code:: python from collections import defaultdict from joy.parser import Symbol @@ -874,7 +874,7 @@ effect comment tuples to reasonable text format. There are some details in how this code works that related to stuff later in the notebook, so you should skip it for now and read it later if you’re interested. -.. code:: ipython2 +.. code:: python def doc_from_stack_effect(inputs, outputs): return '(%s--%s)' % ( @@ -914,7 +914,7 @@ Now we can write a compiler function to emit Python source code. (The underscore suffix distiguishes it from the built-in ``compile()`` function.) -.. code:: ipython2 +.. code:: python def compile_(name, f, doc=None): if doc is None: @@ -932,7 +932,7 @@ function.) Here it is in action: -.. code:: ipython2 +.. code:: python source = compile_('F', F) @@ -949,7 +949,7 @@ Here it is in action: Compare: -.. code:: ipython2 +.. code:: python def F_python(stack): (_, (d, (c, ((a, (b, S0)), stack)))) = stack @@ -957,7 +957,7 @@ Compare: Next steps: -.. code:: ipython2 +.. code:: python L = {} @@ -976,16 +976,16 @@ Next steps: Let’s try it out: -.. code:: ipython2 +.. code:: python from notebook_preamble import D, J, V from joy.library import SimpleFunctionWrapper -.. code:: ipython2 +.. code:: python D['F'] = SimpleFunctionWrapper(L['F']) -.. code:: ipython2 +.. code:: python J('[4 5 ...] 2 3 1 F') @@ -1012,7 +1012,7 @@ Compiling Library Functions We can use ``compile_()`` to generate many primitives in the library from their stack effect comments: -.. code:: ipython2 +.. code:: python def defs(): @@ -1036,7 +1036,7 @@ from their stack effect comments: return locals() -.. code:: ipython2 +.. code:: python for name, stack_effect_comment in sorted(defs().items()): print @@ -1205,7 +1205,7 @@ Python class hierarchy of Joy types and use the ``issubclass()`` method to establish domain ordering, as well as other handy behaviour that will make it fairly easy to reuse most of the code above. -.. code:: ipython2 +.. code:: python class AnyJoyType(object): @@ -1251,14 +1251,14 @@ make it fairly easy to reuse most of the code above. Mess with it a little: -.. code:: ipython2 +.. code:: python from itertools import permutations “Any” types can be specialized to numbers and stacks, but not vice versa: -.. code:: ipython2 +.. code:: python for a, b in permutations((A[0], N[0], S[0]), 2): print a, '>=', b, '->', a >= b @@ -1278,7 +1278,7 @@ Our crude `Numerical Tower `__ of *numbers* > *floats* > *integers* works as well (but we’re not going to use it yet): -.. code:: ipython2 +.. code:: python for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2): print a, '>=', b, '->', a >= b @@ -1303,13 +1303,13 @@ Tower `__ of *numbers* > Typing ``sqr`` ~~~~~~~~~~~~~~ -.. code:: ipython2 +.. code:: python dup = (A[1],), (A[1], A[1]) mul = (N[1], N[2]), (N[3],) -.. code:: ipython2 +.. code:: python dup @@ -1322,7 +1322,7 @@ Typing ``sqr`` -.. code:: ipython2 +.. code:: python mul @@ -1340,7 +1340,7 @@ Modifying the Inferencer Re-labeling still works fine: -.. code:: ipython2 +.. code:: python foo = relabel(dup, mul) @@ -1361,7 +1361,7 @@ Re-labeling still works fine: The ``delabel()`` function needs an overhaul. It now has to keep track of how many labels of each domain it has “seen”. -.. code:: ipython2 +.. code:: python from collections import Counter @@ -1383,7 +1383,7 @@ of how many labels of each domain it has “seen”. return tuple(delabel(inner, seen, c) for inner in f) -.. code:: ipython2 +.. code:: python delabel(foo) @@ -1399,7 +1399,7 @@ of how many labels of each domain it has “seen”. ``unify()`` version 3 ^^^^^^^^^^^^^^^^^^^^^ -.. code:: ipython2 +.. code:: python def unify(u, v, s=None): if s is None: @@ -1449,7 +1449,7 @@ of how many labels of each domain it has “seen”. Rewrite the stack effect comments: -.. code:: ipython2 +.. code:: python def defs(): @@ -1503,11 +1503,11 @@ Rewrite the stack effect comments: return locals() -.. code:: ipython2 +.. code:: python DEFS = defs() -.. code:: ipython2 +.. code:: python for name, stack_effect_comment in sorted(DEFS.items()): print name, '=', doc_from_stack_effect(*stack_effect_comment) @@ -1543,14 +1543,14 @@ Rewrite the stack effect comments: uncons = ([a1 .1.] -- a1 [.1.]) -.. code:: ipython2 +.. code:: python globals().update(DEFS) Compose ``dup`` and ``mul`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -.. code:: ipython2 +.. code:: python C(dup, mul) @@ -1565,7 +1565,7 @@ Compose ``dup`` and ``mul`` Revisit the ``F`` function, works fine. -.. code:: ipython2 +.. code:: python F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons)) F @@ -1579,7 +1579,7 @@ Revisit the ``F`` function, works fine. -.. code:: ipython2 +.. code:: python print doc_from_stack_effect(*F) @@ -1592,12 +1592,12 @@ Revisit the ``F`` function, works fine. Some otherwise inefficient functions are no longer to be feared. We can also get the effect of combinators in some limited cases. -.. code:: ipython2 +.. code:: python def neato(*funcs): print doc_from_stack_effect(*reduce(C, funcs)) -.. code:: ipython2 +.. code:: python # e.g. [swap] dip neato(rollup, swap, rolldown) @@ -1608,7 +1608,7 @@ also get the effect of combinators in some limited cases. (a1 a2 a3 -- a2 a1 a3) -.. code:: ipython2 +.. code:: python # e.g. [popop] dipd neato(popdd, rolldown, pop) @@ -1619,7 +1619,7 @@ also get the effect of combinators in some limited cases. (a1 a2 a3 a4 -- a3 a4) -.. code:: ipython2 +.. code:: python # Reverse the order of the top three items. neato(rollup, swap) @@ -1636,7 +1636,7 @@ also get the effect of combinators in some limited cases. Because the type labels represent themselves as valid Python identifiers the ``compile_()`` function doesn’t need to generate them anymore: -.. code:: ipython2 +.. code:: python def compile_(name, f, doc=None): inputs, outputs = f @@ -1652,7 +1652,7 @@ the ``compile_()`` function doesn’t need to generate them anymore: %s = stack return %s''' % (name, doc, i, o) -.. code:: ipython2 +.. code:: python print compile_('F', F) @@ -1668,7 +1668,7 @@ the ``compile_()`` function doesn’t need to generate them anymore: But it cannot magically create new functions that involve e.g. math and such. Note that this is *not* a ``sqr`` function implementation: -.. code:: ipython2 +.. code:: python print compile_('sqr', C(dup, mul)) @@ -1696,7 +1696,7 @@ The functions that *can* be compiled are the ones that have only ``AnyJoyType`` and ``StackJoyType`` labels in their stack effect comments. We can write a function to check that: -.. code:: ipython2 +.. code:: python from itertools import imap @@ -1704,7 +1704,7 @@ comments. We can write a function to check that: def compilable(f): return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f) -.. code:: ipython2 +.. code:: python for name, stack_effect_comment in sorted(defs().items()): if compilable(stack_effect_comment): @@ -1828,7 +1828,7 @@ the “truthiness” of ``StackJoyType`` to false to let e.g. ``joy.utils.stack.concat`` work with our stack effect comment cons-list tuples.) -.. code:: ipython2 +.. code:: python def compose(f, g): (f_in, f_out), (g_in, g_out) = f, g @@ -1840,7 +1840,7 @@ tuples.) I don’t want to rewrite all the defs myself, so I’ll write a little conversion function instead. This is programmer’s laziness. -.. code:: ipython2 +.. code:: python def sequence_to_stack(seq, stack=StackJoyType(23)): for item in seq: stack = item, stack @@ -1854,7 +1854,7 @@ conversion function instead. This is programmer’s laziness. NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1]) globals().update(NEW_DEFS) -.. code:: ipython2 +.. code:: python C(stack, uncons) @@ -1867,7 +1867,7 @@ conversion function instead. This is programmer’s laziness. -.. code:: ipython2 +.. code:: python reduce(C, (stack, uncons, uncons)) @@ -1887,7 +1887,7 @@ The display function should be changed too. Clunky junk, but it will suffice for now. -.. code:: ipython2 +.. code:: python def doc_from_stack_effect(inputs, outputs): switch = [False] # Do we need to display the '...' for the rest of the main stack? @@ -1935,7 +1935,7 @@ Clunky junk, but it will suffice for now. a.append(end) return '[%s]' % ' '.join(a) -.. code:: ipython2 +.. code:: python for name, stack_effect_comment in sorted(NEW_DEFS.items()): print name, '=', doc_from_stack_effect(*stack_effect_comment) @@ -1973,7 +1973,7 @@ Clunky junk, but it will suffice for now. uncons = ([a1 .1.] -- a1 [.1.]) -.. code:: ipython2 +.. code:: python print ; print doc_from_stack_effect(*stack) print ; print doc_from_stack_effect(*C(stack, uncons)) @@ -1993,7 +1993,7 @@ Clunky junk, but it will suffice for now. (... a1 -- ... a1 [a1 ...]) -.. code:: ipython2 +.. code:: python print doc_from_stack_effect(*C(ccons, stack)) @@ -2003,7 +2003,7 @@ Clunky junk, but it will suffice for now. (... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...]) -.. code:: ipython2 +.. code:: python Q = C(ccons, stack) @@ -2024,7 +2024,7 @@ Clunky junk, but it will suffice for now. This makes the ``compile_()`` function pretty simple as the stack effect comments are now already in the form needed for the Python code: -.. code:: ipython2 +.. code:: python def compile_(name, f, doc=None): i, o = f @@ -2035,7 +2035,7 @@ comments are now already in the form needed for the Python code: %s = stack return %s''' % (name, doc, i, o) -.. code:: ipython2 +.. code:: python print compile_('Q', Q) @@ -2053,12 +2053,12 @@ comments are now already in the form needed for the Python code: -.. code:: ipython2 +.. code:: python unstack = (S[1], S[0]), S[1] enstacken = S[0], (S[0], S[1]) -.. code:: ipython2 +.. code:: python print doc_from_stack_effect(*unstack) @@ -2068,7 +2068,7 @@ comments are now already in the form needed for the Python code: ([.1.] --) -.. code:: ipython2 +.. code:: python print doc_from_stack_effect(*enstacken) @@ -2078,7 +2078,7 @@ comments are now already in the form needed for the Python code: (-- [.0.]) -.. code:: ipython2 +.. code:: python print doc_from_stack_effect(*C(cons, unstack)) @@ -2088,7 +2088,7 @@ comments are now already in the form needed for the Python code: (a1 [.1.] -- a1) -.. code:: ipython2 +.. code:: python print doc_from_stack_effect(*C(cons, enstacken)) @@ -2098,7 +2098,7 @@ comments are now already in the form needed for the Python code: (a1 [.1.] -- [[a1 .1.] .2.]) -.. code:: ipython2 +.. code:: python C(cons, unstack) @@ -2117,7 +2117,7 @@ Part VI: Multiple Stack Effects … -.. code:: ipython2 +.. code:: python class IntJoyType(NumberJoyType): prefix = 'i' @@ -2125,7 +2125,7 @@ Part VI: Multiple Stack Effects F = map(FloatJoyType, _R) I = map(IntJoyType, _R) -.. code:: ipython2 +.. code:: python muls = [ ((I[2], (I[1], S[0])), (I[3], S[0])), @@ -2134,7 +2134,7 @@ Part VI: Multiple Stack Effects ((F[2], (F[1], S[0])), (F[3], S[0])), ] -.. code:: ipython2 +.. code:: python for f in muls: print doc_from_stack_effect(*f) @@ -2148,7 +2148,7 @@ Part VI: Multiple Stack Effects (f1 f2 -- f3) -.. code:: ipython2 +.. code:: python for f in muls: try: @@ -2164,7 +2164,7 @@ Part VI: Multiple Stack Effects (a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2) -.. code:: ipython2 +.. code:: python from itertools import product @@ -2180,7 +2180,7 @@ Part VI: Multiple Stack Effects def MC(F, G): return sorted(set(meta_compose(F, G))) -.. code:: ipython2 +.. code:: python for f in MC([dup], [mul]): print doc_from_stack_effect(*f) @@ -2191,7 +2191,7 @@ Part VI: Multiple Stack Effects (n1 -- n2) -.. code:: ipython2 +.. code:: python for f in MC([dup], muls): print doc_from_stack_effect(*f) @@ -2264,7 +2264,7 @@ Giving us two unifiers: {c: a, d: b, .1.: .0.} {c: a, d: e, .1.: A* b .0.} -.. code:: ipython2 +.. code:: python class KleeneStar(object): @@ -2314,7 +2314,7 @@ Giving us two unifiers: Can now return multiple results… -.. code:: ipython2 +.. code:: python def unify(u, v, s=None): if s is None: @@ -2386,7 +2386,7 @@ Can now return multiple results… def stacky(thing): return thing.__class__ in {AnyJoyType, StackJoyType} -.. code:: ipython2 +.. code:: python a = (As[1], S[1]) a @@ -2400,7 +2400,7 @@ Can now return multiple results… -.. code:: ipython2 +.. code:: python b = (A[1], S[2]) b @@ -2414,7 +2414,7 @@ Can now return multiple results… -.. code:: ipython2 +.. code:: python for result in unify(b, a): print result, '->', update(result, a), update(result, b) @@ -2426,7 +2426,7 @@ Can now return multiple results… {a1: a10001, s2: (a1*, s1)} -> (a1*, s1) (a10001, (a1*, s1)) -.. code:: ipython2 +.. code:: python for result in unify(a, b): print result, '->', update(result, a), update(result, b) @@ -2446,7 +2446,7 @@ Can now return multiple results… (a1*, s1) [a1*] (a2, (a1*, s1)) [a2 a1*] -.. code:: ipython2 +.. code:: python sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0]) @@ -2458,7 +2458,7 @@ Can now return multiple results… ([n1* .1.] -- n0) -.. code:: ipython2 +.. code:: python f = (N[1], (N[2], (N[3], S[1]))), S[0] @@ -2470,7 +2470,7 @@ Can now return multiple results… (-- [n1 n2 n3 .1.]) -.. code:: ipython2 +.. code:: python for result in unify(sum_[0], f): print result, '->', update(result, sum_[1]) @@ -2489,7 +2489,7 @@ Can now return multiple results… This function has to be modified to yield multiple results. -.. code:: ipython2 +.. code:: python def compose(f, g): (f_in, f_out), (g_in, g_out) = f, g @@ -2501,7 +2501,7 @@ This function has to be modified to yield multiple results. -.. code:: ipython2 +.. code:: python def meta_compose(F, G): for f, g in product(F, G): @@ -2517,7 +2517,7 @@ This function has to be modified to yield multiple results. for fg in compose(f, g): yield delabel(fg) -.. code:: ipython2 +.. code:: python for f in MC([dup], muls): print doc_from_stack_effect(*f) @@ -2529,7 +2529,7 @@ This function has to be modified to yield multiple results. (i1 -- i2) -.. code:: ipython2 +.. code:: python @@ -2542,7 +2542,7 @@ This function has to be modified to yield multiple results. ([n1* .1.] -- [n1* .1.] n1) -.. code:: ipython2 +.. code:: python @@ -2556,7 +2556,7 @@ This function has to be modified to yield multiple results. (n1 [n1* .1.] -- n2) -.. code:: ipython2 +.. code:: python sum_ = (((N[1], (Ns[1], S[1])), S[0]), (N[0], S[0])) print doc_from_stack_effect(*cons), @@ -2571,7 +2571,7 @@ This function has to be modified to yield multiple results. (a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n1 [n1* .1.] -- n2) -.. code:: ipython2 +.. code:: python a = (A[4], (As[1], (A[3], S[1]))) a @@ -2585,7 +2585,7 @@ This function has to be modified to yield multiple results. -.. code:: ipython2 +.. code:: python b = (A[1], (A[2], S[2])) b @@ -2599,7 +2599,7 @@ This function has to be modified to yield multiple results. -.. code:: ipython2 +.. code:: python for result in unify(b, a): print result @@ -2611,7 +2611,7 @@ This function has to be modified to yield multiple results. {a1: a4, s2: (a1*, (a3, s1)), a2: a10003} -.. code:: ipython2 +.. code:: python for result in unify(a, b): print result @@ -2681,7 +2681,7 @@ We need a type variable for Joy functions that can go in our expressions and be used by the hybrid inferencer/interpreter. They have to store a name and a list of stack effects. -.. code:: ipython2 +.. code:: python class FunctionJoyType(AnyJoyType): @@ -2703,14 +2703,14 @@ Specialized for Simple Functions and Combinators For non-combinator functions the stack effects list contains stack effect comments (represented by pairs of cons-lists as described above.) -.. code:: ipython2 +.. code:: python class SymbolJoyType(FunctionJoyType): prefix = 'F' For combinators the list contains Python functions. -.. code:: ipython2 +.. code:: python class CombinatorJoyType(FunctionJoyType): @@ -2731,7 +2731,7 @@ For combinators the list contains Python functions. For simple combinators that have only one effect (like ``dip``) you only need one function and it can be the combinator itself. -.. code:: ipython2 +.. code:: python import joy.library @@ -2741,7 +2741,7 @@ For combinators that can have more than one effect (like ``branch``) you have to write functions that each implement the action of one of the effects. -.. code:: ipython2 +.. code:: python def branch_true(stack, expression, dictionary): (then, (else_, (flag, stack))) = stack @@ -2771,7 +2771,7 @@ updated along with the stack effects after doing unification or we risk losing useful information. This was a straightforward, if awkward, modification to the call structure of ``meta_compose()`` et. al. -.. code:: ipython2 +.. code:: python ID = S[0], S[0] # Identity function. @@ -2833,7 +2833,7 @@ cruft to convert the definitions in ``DEFS`` to the new ``SymbolJoyType`` objects, and some combinators. Here is an example of output from the current code : -.. code:: ipython2 +.. code:: python 1/0 # (Don't try to run this cell! It's not going to work. This is "read only" code heh..) @@ -2956,7 +2956,7 @@ module. But if you’re interested in all that you should just use Prolog! Anyhow, type *checking* is a few easy steps away. -.. code:: ipython2 +.. code:: python def _ge(self, other): return (issubclass(other.__class__, self.__class__) diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt index dc4f996..c44343a 100644 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt +++ b/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt @@ -10,7 +10,7 @@ Huet `__ out of sequences. -.. code:: ipython2 +.. code:: python J('[1 [2 [3 4 25 6] 7] 8]') @@ -54,14 +54,14 @@ show the trace so you can see how it works. If we were going to use these a lot it would make sense to write Python versions for efficiency, but see below. -.. code:: ipython2 +.. code:: python define('z-down == [] swap uncons swap') define('z-up == swons swap shunt') define('z-right == [swons] cons dip uncons swap') define('z-left == swons [uncons swap] dip swap') -.. code:: ipython2 +.. code:: python V('[1 [2 [3 4 25 6] 7] 8] z-down') @@ -77,7 +77,7 @@ but see below. [] [[2 [3 4 25 6] 7] 8] 1 . -.. code:: ipython2 +.. code:: python V('[] [[2 [3 4 25 6] 7] 8] 1 z-right') @@ -101,7 +101,7 @@ but see below. [1] [8] [2 [3 4 25 6] 7] . -.. code:: ipython2 +.. code:: python J('[1] [8] [2 [3 4 25 6] 7] z-down') @@ -111,7 +111,7 @@ but see below. [1] [8] [] [[3 4 25 6] 7] 2 -.. code:: ipython2 +.. code:: python J('[1] [8] [] [[3 4 25 6] 7] 2 z-right') @@ -121,7 +121,7 @@ but see below. [1] [8] [2] [7] [3 4 25 6] -.. code:: ipython2 +.. code:: python J('[1] [8] [2] [7] [3 4 25 6] z-down') @@ -131,7 +131,7 @@ but see below. [1] [8] [2] [7] [] [4 25 6] 3 -.. code:: ipython2 +.. code:: python J('[1] [8] [2] [7] [] [4 25 6] 3 z-right') @@ -141,7 +141,7 @@ but see below. [1] [8] [2] [7] [3] [25 6] 4 -.. code:: ipython2 +.. code:: python J('[1] [8] [2] [7] [3] [25 6] 4 z-right') @@ -151,7 +151,7 @@ but see below. [1] [8] [2] [7] [4 3] [6] 25 -.. code:: ipython2 +.. code:: python J('[1] [8] [2] [7] [4 3] [6] 25 sqr') @@ -161,7 +161,7 @@ but see below. [1] [8] [2] [7] [4 3] [6] 625 -.. code:: ipython2 +.. code:: python V('[1] [8] [2] [7] [4 3] [6] 625 z-up') @@ -184,7 +184,7 @@ but see below. [1] [8] [2] [7] [3 4 625 6] . -.. code:: ipython2 +.. code:: python J('[1] [8] [2] [7] [3 4 625 6] z-up') @@ -194,7 +194,7 @@ but see below. [1] [8] [2 [3 4 625 6] 7] -.. code:: ipython2 +.. code:: python J('[1] [8] [2 [3 4 625 6] 7] z-up') @@ -210,7 +210,7 @@ but see below. In Joy we have the ``dip`` and ``infra`` combinators which can “target” or “address” any particular item in a Joy tree structure. -.. code:: ipython2 +.. code:: python V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra') @@ -270,13 +270,13 @@ been embedded in a nested series of quoted programs, e.g.: The ``Z`` function isn’t hard to make. -.. code:: ipython2 +.. code:: python define('Z == [[] cons cons] step i') Here it is in action in a simplified scenario. -.. code:: ipython2 +.. code:: python V('1 [2 3 4] Z') @@ -314,7 +314,7 @@ Here it is in action in a simplified scenario. And here it is doing the main thing. -.. code:: ipython2 +.. code:: python J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z') diff --git a/docs/sphinx_docs/_build/html/lib.html b/docs/sphinx_docs/_build/html/lib.html index 7783c89..03f9a10 100644 --- a/docs/sphinx_docs/_build/html/lib.html +++ b/docs/sphinx_docs/_build/html/lib.html @@ -35,7 +35,7 @@

Functions Grouped by, er, Function with Examples¶

-
from notebook_preamble import J, V
+
from notebook_preamble import J, V
 
@@ -48,7 +48,7 @@ static for the duration of the computation. This remains to be done but it’s “off the shelf” technology.)

clear¶

-
J('1 2 3 clear')
+
J('1 2 3 clear')
 
(nothing)
@@ -57,13 +57,13 @@ it’s “off the shelf” technology.)

dup dupd¶

-
J('1 2 3 dup')
+
J('1 2 3 dup')
 
1 2 3 3
 
-
J('1 2 3 dupd')
+
J('1 2 3 dupd')
 
1 2 2 3
@@ -74,27 +74,27 @@ it’s “off the shelf” technology.)

enstacken disenstacken stack unstack¶

(I may have these paired up wrong. I.e. disenstacken should be unstack and vice versa.)

-
J('1 2 3 enstacken') # Replace the stack with a quote of itself.
+
J('1 2 3 enstacken') # Replace the stack with a quote of itself.
 
[3 2 1]
 
-
J('4 5 6 [3 2 1] disenstacken')  # Unpack a list onto the stack.
+
J('4 5 6 [3 2 1] disenstacken')  # Unpack a list onto the stack.
 
4 5 6 3 2 1
 
-
J('1 2 3 stack')  # Get the stack on the stack.
+
J('1 2 3 stack')  # Get the stack on the stack.
 
1 2 3 [3 2 1]
 
-
J('1 2 3 [4 5 6] unstack')  # Replace the stack with the list on top.
-                            # The items appear reversed but they are not,
-                            # 4 is on the top of both the list and the stack.
+
J('1 2 3 [4 5 6] unstack')  # Replace the stack with the list on top.
+                            # The items appear reversed but they are not,
+                            # 4 is on the top of both the list and the stack.
 
6 5 4
@@ -103,19 +103,19 @@ it’s “off the shelf” technology.)

pop popd popop¶

-
J('1 2 3 pop')
+
J('1 2 3 pop')
 
1 2
 
-
J('1 2 3 popd')
+
J('1 2 3 popd')
 
1 3
 
-
J('1 2 3 popop')
+
J('1 2 3 popop')
 
1
@@ -126,13 +126,13 @@ it’s “off the shelf” technology.)

roll< rolldown roll> rollup¶

The “down” and “up” refer to the movement of two of the top three items (displacing the third.)

-
J('1 2 3 roll<')
+
J('1 2 3 roll<')
 
2 3 1
 
-
J('1 2 3 roll>')
+
J('1 2 3 roll>')
 
3 1 2
@@ -141,7 +141,7 @@ it’s “off the shelf” technology.)

swap¶

-
J('1 2 3 swap')
+
J('1 2 3 swap')
 
1 3 2
@@ -150,13 +150,13 @@ it’s “off the shelf” technology.)

tuck over¶

-
J('1 2 3 tuck')
+
J('1 2 3 tuck')
 
1 3 2 3
 
-
J('1 2 3 over')
+
J('1 2 3 over')
 
1 2 3 2
@@ -165,25 +165,25 @@ it’s “off the shelf” technology.)

unit quoted unquoted¶

-
J('1 2 3 unit')
+
J('1 2 3 unit')
 
1 2 [3]
 
-
J('1 2 3 quoted')
+
J('1 2 3 quoted')
 
1 [2] 3
 
-
J('1 [2] 3 unquoted')
+
J('1 [2] 3 unquoted')
 
1 2 3
 
-
V('1 [dup] 3 unquoted')  # Unquoting evaluates.  Be aware.
+
V('1 [dup] 3 unquoted')  # Unquoting evaluates.  Be aware.
 
              . 1 [dup] 3 unquoted
@@ -204,19 +204,19 @@ it’s “off the shelf” technology.)

List words¶

concat swoncat shunt¶

-
J('[1 2 3] [4 5 6] concat')
+
J('[1 2 3] [4 5 6] concat')
 
[1 2 3 4 5 6]
 
-
J('[1 2 3] [4 5 6] swoncat')
+
J('[1 2 3] [4 5 6] swoncat')
 
[4 5 6 1 2 3]
 
-
J('[1 2 3] [4 5 6] shunt')
+
J('[1 2 3] [4 5 6] shunt')
 
[6 5 4 1 2 3]
@@ -225,19 +225,19 @@ it’s “off the shelf” technology.)

cons swons uncons¶

-
J('1 [2 3] cons')
+
J('1 [2 3] cons')
 
[1 2 3]
 
-
J('[2 3] 1 swons')
+
J('[2 3] 1 swons')
 
[1 2 3]
 
-
J('[1 2 3] uncons')
+
J('[1 2 3] uncons')
 
1 [2 3]
@@ -246,25 +246,25 @@ it’s “off the shelf” technology.)

first second third rest¶

-
J('[1 2 3 4] first')
+
J('[1 2 3 4] first')
 
1
 
-
J('[1 2 3 4] second')
+
J('[1 2 3 4] second')
 
2
 
-
J('[1 2 3 4] third')
+
J('[1 2 3 4] third')
 
3
 
-
J('[1 2 3 4] rest')
+
J('[1 2 3 4] rest')
 
[2 3 4]
@@ -273,7 +273,7 @@ it’s “off the shelf” technology.)

flatten¶

-
J('[[1] [2 [3] 4] [5 6]] flatten')
+
J('[[1] [2 [3] 4] [5 6]] flatten')
 
[1 2 [3] 4 5 6]
@@ -283,31 +283,31 @@ it’s “off the shelf” technology.)

getitem at of drop take¶

at and getitem are the same function. of == swap at

-
J('[10 11 12 13 14] 2 getitem')
+
J('[10 11 12 13 14] 2 getitem')
 
12
 
-
J('[1 2 3 4] 0 at')
+
J('[1 2 3 4] 0 at')
 
1
 
-
J('2 [1 2 3 4] of')
+
J('2 [1 2 3 4] of')
 
3
 
-
J('[1 2 3 4] 2 drop')
+
J('[1 2 3 4] 2 drop')
 
[3 4]
 
-
J('[1 2 3 4] 2 take')  # reverses the order
+
J('[1 2 3 4] 2 take')  # reverses the order
 
[2 1]
@@ -317,7 +317,7 @@ it’s “off the shelf” technology.)

remove¶

-
J('[1 2 3 1 4] 1 remove')
+
J('[1 2 3 1 4] 1 remove')
 
[2 3 1 4]
@@ -326,7 +326,7 @@ it’s “off the shelf” technology.)

reverse¶

-
J('[1 2 3 4] reverse')
+
J('[1 2 3 4] reverse')
 
[4 3 2 1]
@@ -335,7 +335,7 @@ it’s “off the shelf” technology.)

size¶

-
J('[1 1 1 1] size')
+
J('[1 1 1 1] size')
 
4
@@ -347,7 +347,7 @@ it’s “off the shelf” technology.)

“Swap stack” swap the list on the top of the stack for the stack, and put the old stack on top of the new one. Think of it as a context switch. Niether of the lists/stacks change their order.

-
J('1 2 3 [4 5 6] swaack')
+
J('1 2 3 [4 5 6] swaack')
 
6 5 4 [3 2 1]
@@ -356,25 +356,25 @@ switch. Niether of the lists/stacks change their order.

choice select¶

-
J('23 9 1 choice')
+
J('23 9 1 choice')
 
9
 
-
J('23 9 0 choice')
+
J('23 9 0 choice')
 
23
 
-
J('[23 9 7] 1 select')  # select is basically getitem, should retire it?
+
J('[23 9 7] 1 select')  # select is basically getitem, should retire it?
 
9
 
-
J('[23 9 7] 0 select')
+
J('[23 9 7] 0 select')
 
23
@@ -383,13 +383,13 @@ switch. Niether of the lists/stacks change their order.

zip¶

-
J('[1 2 3] [6 5 4] zip')
+
J('[1 2 3] [6 5 4] zip')
 
[[6 1] [5 2] [4 3]]
 
-
J('[1 2 3] [6 5 4] zip [sum] map')
+
J('[1 2 3] [6 5 4] zip [sum] map')
 
[7 7 7]
@@ -401,7 +401,7 @@ switch. Niether of the lists/stacks change their order.

Math words¶

+ add¶

-
J('23 9 +')
+
J('23 9 +')
 
32
@@ -410,7 +410,7 @@ switch. Niether of the lists/stacks change their order.

- sub¶

-
J('23 9 -')
+
J('23 9 -')
 
14
@@ -419,7 +419,7 @@ switch. Niether of the lists/stacks change their order.

* mul¶

-
J('23 9 *')
+
J('23 9 *')
 
207
@@ -428,37 +428,37 @@ switch. Niether of the lists/stacks change their order.

/ div floordiv truediv¶

-
J('23 9 /')
+
J('23 9 /')
 
2.5555555555555554
 
-
J('23 -9 truediv')
+
J('23 -9 truediv')
 
-2.5555555555555554
 
-
J('23 9 div')
+
J('23 9 div')
 
2
 
-
J('23 9 floordiv')
+
J('23 9 floordiv')
 
2
 
-
J('23 -9 div')
+
J('23 -9 div')
 
-3
 
-
J('23 -9 floordiv')
+
J('23 -9 floordiv')
 
-3
@@ -467,7 +467,7 @@ switch. Niether of the lists/stacks change their order.

% mod modulus rem remainder¶

-
J('23 9 %')
+
J('23 9 %')
 
5
@@ -476,7 +476,7 @@ switch. Niether of the lists/stacks change their order.

neg¶

-
J('23 neg -5 neg')
+
J('23 neg -5 neg')
 
-23 5
@@ -485,7 +485,7 @@ switch. Niether of the lists/stacks change their order.

pow¶

-
J('2 10 pow')
+
J('2 10 pow')
 
1024
@@ -494,13 +494,13 @@ switch. Niether of the lists/stacks change their order.

sqr sqrt¶

-
J('23 sqr')
+
J('23 sqr')
 
529
 
-
J('23 sqrt')
+
J('23 sqrt')
 
4.795831523312719
@@ -509,13 +509,13 @@ switch. Niether of the lists/stacks change their order.

++ succ -- pred¶

-
J('1 ++')
+
J('1 ++')
 
2
 
-
J('1 --')
+
J('1 --')
 
0
@@ -524,13 +524,13 @@ switch. Niether of the lists/stacks change their order.

<< lshift >> rshift¶

-
J('8 1 <<')
+
J('8 1 <<')
 
16
 
-
J('8 1 >>')
+
J('8 1 >>')
 
4
@@ -539,7 +539,7 @@ switch. Niether of the lists/stacks change their order.

average¶

-
J('[1 2 3 5] average')
+
J('[1 2 3 5] average')
 
2.75
@@ -548,19 +548,19 @@ switch. Niether of the lists/stacks change their order.

range range_to_zero down_to_zero¶

-
J('5 range')
+
J('5 range')
 
[4 3 2 1 0]
 
-
J('5 range_to_zero')
+
J('5 range_to_zero')
 
[0 1 2 3 4 5]
 
-
J('5 down_to_zero')
+
J('5 down_to_zero')
 
5 4 3 2 1 0
@@ -569,7 +569,7 @@ switch. Niether of the lists/stacks change their order.

product¶

-
J('[1 2 3 5] product')
+
J('[1 2 3 5] product')
 
30
@@ -578,7 +578,7 @@ switch. Niether of the lists/stacks change their order.

sum¶

-
J('[1 2 3 5] sum')
+
J('[1 2 3 5] sum')
 
11
@@ -587,7 +587,7 @@ switch. Niether of the lists/stacks change their order.

min¶

-
J('[1 2 3 5] min')
+
J('[1 2 3 5] min')
 
1
@@ -596,7 +596,7 @@ switch. Niether of the lists/stacks change their order.

gcd¶

-
J('45 30 gcd')
+
J('45 30 gcd')
 
15
@@ -607,13 +607,13 @@ switch. Niether of the lists/stacks change their order.

least_fraction¶

If we represent fractions as a quoted pair of integers [q d] this word reduces them to their … least common factors or whatever.

-
J('[45 30] least_fraction')
+
J('[45 30] least_fraction')
 
[3 2]
 
-
J('[23 12] least_fraction')
+
J('[23 12] least_fraction')
 
[23 12]
@@ -626,19 +626,19 @@ reduces them to their … least common factors or whatever.

? truthy¶

Get the Boolean value of the item on the top of the stack.

-
J('23 truthy')
+
J('23 truthy')
 
True
 
-
J('[] truthy')  # Python semantics.
+
J('[] truthy')  # Python semantics.
 
False
 
-
J('0 truthy')
+
J('0 truthy')
 
False
@@ -647,7 +647,7 @@ reduces them to their … least common factors or whatever.

? == dup truthy
 
-
V('23 ?')
+
V('23 ?')
 
        . 23 ?
@@ -657,13 +657,13 @@ reduces them to their … least common factors or whatever.

23 True .
-
J('[] ?')
+
J('[] ?')
 
[] False
 
-
J('0 ?')
+
J('0 ?')
 
0 False
@@ -672,7 +672,7 @@ reduces them to their … least common factors or whatever.

& and¶

-
J('23 9 &')
+
J('23 9 &')
 
1
@@ -681,7 +681,7 @@ reduces them to their … least common factors or whatever.

!= <> ne¶

-
J('23 9 !=')
+
J('23 9 !=')
 
True
@@ -694,13 +694,13 @@ reduces them to their … least common factors or whatever.

^ xor¶

-
J('1 1 ^')
+
J('1 1 ^')
 
0
 
-
J('1 0 ^')
+
J('1 0 ^')
 
1
@@ -712,7 +712,7 @@ reduces them to their … least common factors or whatever.

Miscellaneous¶

help¶

-
J('[help] help')
+
J('[help] help')
 
Accepts a quoted symbol on the top of the stack and prints its docs.
@@ -721,13 +721,13 @@ reduces them to their … least common factors or whatever.

parse¶

-
J('[parse] help')
+
J('[parse] help')
 
Parse the string on the stack to a Joy expression.
 
-
J('1 "2 [3] dup" parse')
+
J('1 "2 [3] dup" parse')
 
1 [2 [3] dup]
@@ -737,7 +737,7 @@ reduces them to their … least common factors or whatever.

run¶

Evaluate a quoted Joy sequence.

-
J('[1 2 dup + +] run')
+
J('[1 2 dup + +] run')
 
[5]
@@ -749,7 +749,7 @@ reduces them to their … least common factors or whatever.

Combinators¶

app1 app2 app3¶

-
J('[app1] help')
+
J('[app1] help')
 
Given a quoted program on TOS and anything as the second stack item run
@@ -761,19 +761,19 @@ reduces them to their … least common factors or whatever.

... [x ...] [Q] . infra first
-
J('10 4 [sqr *] app1')
+
J('10 4 [sqr *] app1')
 
10 160
 
-
J('10 3 4 [sqr *] app2')
+
J('10 3 4 [sqr *] app2')
 
10 90 160
 
-
J('[app2] help')
+
J('[app2] help')
 
Like app1 with two items.
@@ -784,7 +784,7 @@ reduces them to their … least common factors or whatever.

[x ...] [Q] infra first
-
J('10 2 3 4 [sqr *] app3')
+
J('10 2 3 4 [sqr *] app3')
 
10 40 90 160
@@ -804,7 +804,7 @@ function [G]
 
range == [0 <=] [1 - dup] anamorphism
 
-
J('3 [0 <=] [1 - dup] anamorphism')
+
J('3 [0 <=] [1 - dup] anamorphism')
 
[2 1 0]
@@ -813,13 +813,13 @@ function [G]
 

branch¶

-
J('3 4 1 [+] [*] branch')
+
J('3 4 1 [+] [*] branch')
 
12
 
-
J('3 4 0 [+] [*] branch')
+
J('3 4 0 [+] [*] branch')
 
7
@@ -846,7 +846,7 @@ in terms of app2
cleave == [i] app2 [popd] dip
 
-
J('10 2 [+] [-] cleave')
+
J('10 2 [+] [-] cleave')
 
10 12 8
@@ -855,19 +855,19 @@ in terms of app2
 

dip dipd dipdd¶

-
J('1 2 3 4 5 [+] dip')
+
J('1 2 3 4 5 [+] dip')
 
1 2 7 5
 
-
J('1 2 3 4 5 [+] dipd')
+
J('1 2 3 4 5 [+] dipd')
 
1 5 4 5
 
-
J('1 2 3 4 5 [+] dipdd')
+
J('1 2 3 4 5 [+] dipdd')
 
3 3 4 5
@@ -881,7 +881,7 @@ in terms of app2
n [Q] dupdip == n Q n
 
-
V('23 [++] dupdip *')  # N(N + 1)
+
V('23 [++] dupdip *')  # N(N + 1)
 
        . 23 [++] dupdip *
@@ -896,7 +896,7 @@ in terms of app2
 

genrec primrec¶

-
J('[genrec] help')
+
J('[genrec] help')
 
General Recursion Combinator.
@@ -945,7 +945,7 @@ in terms of app2)
 
-
J('3 [1 <=] [] [dup --] [i *] genrec')
+
J('3 [1 <=] [] [dup --] [i *] genrec')
 
6
@@ -954,7 +954,7 @@ in terms of app2
 

i¶

-
V('1 2 3 [+ +] i')
+
V('1 2 3 [+ +] i')
 
            . 1 2 3 [+ +] i
@@ -973,13 +973,13 @@ in terms of app2
[predicate] [then] [else] ifte
 
-
J('1 2 [1] [+] [*] ifte')
+
J('1 2 [1] [+] [*] ifte')
 
3
 
-
J('1 2 [0] [+] [*] ifte')
+
J('1 2 [0] [+] [*] ifte')
 
2
@@ -988,7 +988,7 @@ in terms of app2
 

infra¶

-
V('1 2 3 [4 5 6] [* +] infra')
+
V('1 2 3 [4 5 6] [* +] infra')
 
                    . 1 2 3 [4 5 6] [* +] infra
@@ -1007,7 +1007,7 @@ in terms of app2
 

loop¶

-
J('[loop] help')
+
J('[loop] help')
 
Basic loop combinator.
@@ -1021,7 +1021,7 @@ in terms of app2...
 
-
V('3 dup [1 - dup] loop')
+
V('3 dup [1 - dup] loop')
 
              . 3 dup [1 - dup] loop
@@ -1049,13 +1049,13 @@ in terms of app2
 

map pam¶

-
J('10 [1 2 3] [*] map')
+
J('10 [1 2 3] [*] map')
 
10 [10 20 30]
 
-
J('10 5 [[*][/][+][-]] pam')
+
J('10 5 [[*][/][+][-]] pam')
 
10 5 [50 2.0 15 5]
@@ -1066,25 +1066,25 @@ in terms of app2nullary unary binary ternary¶
 

Run a quoted program enforcing arity.

-
J('1 2 3 4 5 [+] nullary')
+
J('1 2 3 4 5 [+] nullary')
 
1 2 3 4 5 9
 
-
J('1 2 3 4 5 [+] unary')
+
J('1 2 3 4 5 [+] unary')
 
1 2 3 4 9
 
-
J('1 2 3 4 5 [+] binary')  # + has arity 2 so this is technically pointless...
+
J('1 2 3 4 5 [+] binary')  # + has arity 2 so this is technically pointless...
 
1 2 3 9
 
-
J('1 2 3 4 5 [+] ternary')
+
J('1 2 3 4 5 [+] ternary')
 
1 2 9
@@ -1093,7 +1093,7 @@ in terms of app2
 

step¶

-
J('[step] help')
+
J('[step] help')
 
Run a quoted program on each item in a sequence.
@@ -1116,7 +1116,7 @@ in terms of app2on top of the stack.
 
-
V('0 [1 2 3] [+] step')
+
V('0 [1 2 3] [+] step')
 
              . 0 [1 2 3] [+] step
@@ -1141,7 +1141,7 @@ in terms of app2
 

times¶

-
V('3 2 1 2 [+] times')
+
V('3 2 1 2 [+] times')
 
            . 3 2 1 2 [+] times
@@ -1161,7 +1161,7 @@ in terms of app2
 

b¶

-
J('[b] help')
+
J('[b] help')
 
b == [i] dip i
@@ -1170,7 +1170,7 @@ in terms of app2... [P] [Q] b == ... P Q
 
-
V('1 2 [3] [4] b')
+
V('1 2 [3] [4] b')
 
            . 1 2 [3] [4] b
@@ -1189,7 +1189,7 @@ in terms of app2
[predicate] [body] while
 
-
J('3 [0 >] [dup --] while')
+
J('3 [0 >] [dup --] while')
 
3 2 1 0
@@ -1198,7 +1198,7 @@ in terms of app2
 

x¶

-
J('[x] help')
+
J('[x] help')
 
x == dup i
@@ -1208,7 +1208,7 @@ in terms of app2... [Q] x = ... [Q]  Q
 
-
V('1 [2] [i 3] x')  # Kind of a pointless example.
+
V('1 [2] [i 3] x')  # Kind of a pointless example.
 
            . 1 [2] [i 3] x
@@ -1231,25 +1231,25 @@ in terms of app2
 over quote-only datastructures (that is, datastructures that consist
 soley of containers, without strings or numbers or anything else.)

-
J('[] void')
+
J('[] void')
 
False
 
-
J('[[]] void')
+
J('[[]] void')
 
True
 
-
J('[[][[]]] void')
+
J('[[][[]]] void')
 
True
 
-
J('[[[]][[][]]] void')
+
J('[[[]][[][]]] void')
 
False
diff --git a/docs/sphinx_docs/_build/html/notebooks/Derivatives_of_Regular_Expressions.html b/docs/sphinx_docs/_build/html/notebooks/Derivatives_of_Regular_Expressions.html
index 9123462..8c2e135 100644
--- a/docs/sphinx_docs/_build/html/notebooks/Derivatives_of_Regular_Expressions.html
+++ b/docs/sphinx_docs/_build/html/notebooks/Derivatives_of_Regular_Expressions.html
@@ -96,15 +96,15 @@ R∘λ = λ∘R = R
 

Implementation¶

-
from functools import partial as curry
-from itertools import product
+
from functools import partial as curry
+from itertools import product
 

ϕ and λ¶

The empty set and the set of just the empty string.

-
phi = frozenset()   # ϕ
-y = frozenset({''}) # λ
+
phi = frozenset()   # ϕ
+y = frozenset({''}) # λ
 
@@ -115,7 +115,7 @@ illustrate the algorithm and because you can represent any other 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.

-
syms = O, l = frozenset({'0'}), frozenset({'1'})
+
syms = O, l = frozenset({'0'}), frozenset({'1'})
 
@@ -133,7 +133,7 @@ expression is one of:

Where R and S stand for regular expressions.

-
AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split()  # Tags are just strings.
+
AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split()  # Tags are just strings.
 

Because they are formed of frozenset, tuple and str objects @@ -141,36 +141,36 @@ only, these datastructures are immutable.

String Representation of RE Datastructures¶

-
def stringy(re):
-    '''
-    Return a nice string repr for a regular expression datastructure.
-    '''
-    if re == I: return '.'
-    if re in syms: return next(iter(re))
-    if re == y: return '^'
-    if re == phi: return 'X'
-
-    assert isinstance(re, tuple), repr(re)
-    tag = re[0]
-
-    if tag == KSTAR:
-        body = stringy(re[1])
-        if not body: return body
-        if len(body) > 1: return '(' + body + ")*"
-        return body + '*'
-
-    if tag == NOT:
-        body = stringy(re[1])
-        if not body: return body
-        if len(body) > 1: return '(' + body + ")'"
-        return body + "'"
-
-    r, s = stringy(re[1]), stringy(re[2])
-    if tag == CONS: return r + s
-    if tag == OR:   return '%s | %s' % (r, s)
-    if tag == AND:  return '(%s) & (%s)' % (r, s)
-
-    raise ValueError
+
def stringy(re):
+    '''
+    Return a nice string repr for a regular expression datastructure.
+    '''
+    if re == I: return '.'
+    if re in syms: return next(iter(re))
+    if re == y: return '^'
+    if re == phi: return 'X'
+
+    assert isinstance(re, tuple), repr(re)
+    tag = re[0]
+
+    if tag == KSTAR:
+        body = stringy(re[1])
+        if not body: return body
+        if len(body) > 1: return '(' + body + ")*"
+        return body + '*'
+
+    if tag == NOT:
+        body = stringy(re[1])
+        if not body: return body
+        if len(body) > 1: return '(' + body + ")'"
+        return body + "'"
+
+    r, s = stringy(re[1]), stringy(re[2])
+    if tag == CONS: return r + s
+    if tag == OR:   return '%s | %s' % (r, s)
+    if tag == AND:  return '(%s) & (%s)' % (r, s)
+
+    raise ValueError
 
@@ -180,10 +180,10 @@ only, these datastructures are immutable.

I = (0|1)*
 
-
I = (KSTAR, (OR, O, l))
+
I = (KSTAR, (OR, O, l))
 
-
print stringy(I)
+
print stringy(I)
 
.
@@ -198,13 +198,13 @@ only, these datastructures are immutable.

Note that it contains one of everything.

-
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)))
+
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)))
 
-
print stringy(it)
+
print stringy(it)
 
(.111.) & ((.01 | 11*)')
@@ -214,36 +214,36 @@ it = (AND, a, (NOT, (OR, b, c)))
 

nully()¶

Let’s get that auxiliary predicate function δ out of the way.

-
def nully(R):
-    '''
-    δ - Return λ if λ ⊆ R otherwise ϕ.
-    '''
+
def nully(R):
+    '''
+    δ - Return λ if λ ⊆ R otherwise ϕ.
+    '''
 
-    # δ(a) → ϕ
-    # δ(ϕ) → ϕ
-    if R in syms or R == phi:
-        return phi
+    # δ(a) → ϕ
+    # δ(ϕ) → ϕ
+    if R in syms or R == phi:
+        return phi
 
-    # δ(λ) → λ
-    if R == y:
-        return y
+    # δ(λ) → λ
+    if R == y:
+        return y
 
-    tag = R[0]
+    tag = R[0]
 
-    # δ(R*) → λ
-    if tag == KSTAR:
-        return y
+    # δ(R*) → λ
+    if tag == KSTAR:
+        return y
 
-    # δ(¬R) δ(R)≟ϕ → λ
-    # δ(¬R) δ(R)≟λ → ϕ
-    if tag == NOT:
-        return phi if nully(R[1]) else y
+    # δ(¬R) δ(R)≟ϕ → λ
+    # δ(¬R) δ(R)≟λ → ϕ
+    if tag == NOT:
+        return phi if nully(R[1]) else y
 
-    # δ(R∘S) → δ(R) ∧ δ(S)
-    # δ(R ∧ S) → δ(R) ∧ δ(S)
-    # δ(R ∨ S) → δ(R) ∨ δ(S)
-    r, s = nully(R[1]), nully(R[2])
-    return r & s if tag in {AND, CONS} else r | s
+    # δ(R∘S) → δ(R) ∧ δ(S)
+    # δ(R ∧ S) → δ(R) ∧ δ(S)
+    # δ(R ∨ S) → δ(R) ∨ δ(S)
+    r, s = nully(R[1]), nully(R[2])
+    return r & s if tag in {AND, CONS} else r | s
 
@@ -252,71 +252,71 @@ it = (AND, a, (NOT, (OR, b, c)))

This is the straightforward version with no “compaction”. It works fine, but does waaaay too much work because the expressions grow each derivation.

-
def D(symbol):
+
def D(symbol):
 
-    def derv(R):
+    def derv(R):
 
-        # ∂a(a) → λ
-        if R == {symbol}:
-            return y
+        # ∂a(a) → λ
+        if R == {symbol}:
+            return y
 
-        # ∂a(λ) → ϕ
-        # ∂a(ϕ) → ϕ
-        # ∂a(¬a) → ϕ
-        if R == y or R == phi or R in syms:
-            return phi
+        # ∂a(λ) → ϕ
+        # ∂a(ϕ) → ϕ
+        # ∂a(¬a) → ϕ
+        if R == y or R == phi or R in syms:
+            return phi
 
-        tag = R[0]
+        tag = R[0]
 
-        # ∂a(R*) → ∂a(R)∘R*
-        if tag == KSTAR:
-            return (CONS, derv(R[1]), R)
+        # ∂a(R*) → ∂a(R)∘R*
+        if tag == KSTAR:
+            return (CONS, derv(R[1]), R)
 
-        # ∂a(¬R) → ¬∂a(R)
-        if tag == NOT:
-            return (NOT, derv(R[1]))
+        # ∂a(¬R) → ¬∂a(R)
+        if tag == NOT:
+            return (NOT, derv(R[1]))
 
-        r, s = R[1:]
+        r, s = R[1:]
 
-        # ∂a(R∘S) → ∂a(R)∘S ∨ δ(R)∘∂a(S)
-        if tag == CONS:
-            A = (CONS, derv(r), s)  # A = ∂a(R)∘S
-            # A ∨ δ(R) ∘ ∂a(S)
-            # A ∨  λ   ∘ ∂a(S) → A ∨ ∂a(S)
-            # A ∨  ϕ   ∘ ∂a(S) → A ∨ ϕ → A
-            return (OR, A, derv(s)) if nully(r) else A
+        # ∂a(R∘S) → ∂a(R)∘S ∨ δ(R)∘∂a(S)
+        if tag == CONS:
+            A = (CONS, derv(r), s)  # A = ∂a(R)∘S
+            # A ∨ δ(R) ∘ ∂a(S)
+            # A ∨  λ   ∘ ∂a(S) → A ∨ ∂a(S)
+            # A ∨  ϕ   ∘ ∂a(S) → A ∨ ϕ → A
+            return (OR, A, derv(s)) if nully(r) else A
 
-        # ∂a(R ∧ S) → ∂a(R) ∧ ∂a(S)
-        # ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S)
-        return (tag, derv(r), derv(s))
+        # ∂a(R ∧ S) → ∂a(R) ∧ ∂a(S)
+        # ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S)
+        return (tag, derv(r), derv(s))
 
-    return derv
+    return derv
 

Compaction Rules¶

-
def _compaction_rule(relation, one, zero, a, b):
-    return (
-        b if a == one else  # R*1 = 1*R = R
-        a if b == one else
-        zero if a == zero or b == zero else  # R*0 = 0*R = 0
-        (relation, a, b)
-        )
+
def _compaction_rule(relation, one, zero, a, b):
+    return (
+        b if a == one else  # R*1 = 1*R = R
+        a if b == one else
+        zero if a == zero or b == zero else  # R*0 = 0*R = 0
+        (relation, a, b)
+        )
 

An elegant symmetry.

-
# R ∧ I = I ∧ R = R
-# R ∧ ϕ = ϕ ∧ R = ϕ
-_and = curry(_compaction_rule, AND, I, phi)
+
# R ∧ I = I ∧ R = R
+# R ∧ ϕ = ϕ ∧ R = ϕ
+_and = curry(_compaction_rule, AND, I, phi)
 
-# R ∨ ϕ = ϕ ∨ R = R
-# R ∨ I = I ∨ R = I
-_or = curry(_compaction_rule, OR, phi, I)
+# R ∨ ϕ = ϕ ∨ R = R
+# R ∨ I = I ∨ R = I
+_or = curry(_compaction_rule, OR, phi, I)
 
-# R∘λ = λ∘R = R
-# R∘ϕ = ϕ∘R = ϕ
-_cons = curry(_compaction_rule, CONS, y, phi)
+# R∘λ = λ∘R = R
+# R∘ϕ = ϕ∘R = ϕ
+_cons = curry(_compaction_rule, CONS, y, phi)
 
@@ -325,21 +325,21 @@ _cons = curry(_compaction_rule, CONS, y, phi)

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.

-
class Memo(object):
+
class Memo(object):
 
-    def __init__(self, f):
-        self.f = f
-        self.calls = self.hits = 0
-        self.mem = {}
+    def __init__(self, f):
+        self.f = f
+        self.calls = self.hits = 0
+        self.mem = {}
 
-    def __call__(self, key):
-        self.calls += 1
-        try:
-            result = self.mem[key]
-            self.hits += 1
-        except KeyError:
-            result = self.mem[key] = self.f(key)
-        return result
+    def __call__(self, key):
+        self.calls += 1
+        try:
+            result = self.mem[key]
+            self.hits += 1
+        except KeyError:
+            result = self.mem[key] = self.f(key)
+        return result
 
@@ -347,47 +347,47 @@ are pure so this is fine.

With “Compaction”¶

This version uses the rules above to perform compaction. It keeps the expressions from growing too large.

-
def D_compaction(symbol):
+
def D_compaction(symbol):
 
-    @Memo
-    def derv(R):
+    @Memo
+    def derv(R):
 
-        # ∂a(a) → λ
-        if R == {symbol}:
-            return y
+        # ∂a(a) → λ
+        if R == {symbol}:
+            return y
 
-        # ∂a(λ) → ϕ
-        # ∂a(ϕ) → ϕ
-        # ∂a(¬a) → ϕ
-        if R == y or R == phi or R in syms:
-            return phi
+        # ∂a(λ) → ϕ
+        # ∂a(ϕ) → ϕ
+        # ∂a(¬a) → ϕ
+        if R == y or R == phi or R in syms:
+            return phi
 
-        tag = R[0]
+        tag = R[0]
 
-        # ∂a(R*) → ∂a(R)∘R*
-        if tag == KSTAR:
-            return _cons(derv(R[1]), R)
+        # ∂a(R*) → ∂a(R)∘R*
+        if tag == KSTAR:
+            return _cons(derv(R[1]), R)
 
-        # ∂a(¬R) → ¬∂a(R)
-        if tag == NOT:
-            return (NOT, derv(R[1]))
+        # ∂a(¬R) → ¬∂a(R)
+        if tag == NOT:
+            return (NOT, derv(R[1]))
 
-        r, s = R[1:]
+        r, s = R[1:]
 
-        # ∂a(R∘S) → ∂a(R)∘S ∨ δ(R)∘∂a(S)
-        if tag == CONS:
-            A = _cons(derv(r), s)  # A = ∂a(r)∘s
-            # A ∨ δ(R) ∘ ∂a(S)
-            # A ∨  λ   ∘ ∂a(S) → A ∨ ∂a(S)
-            # A ∨  ϕ   ∘ ∂a(S) → A ∨ ϕ → A
-            return _or(A, derv(s)) if nully(r) else A
+        # ∂a(R∘S) → ∂a(R)∘S ∨ δ(R)∘∂a(S)
+        if tag == CONS:
+            A = _cons(derv(r), s)  # A = ∂a(r)∘s
+            # A ∨ δ(R) ∘ ∂a(S)
+            # A ∨  λ   ∘ ∂a(S) → A ∨ ∂a(S)
+            # A ∨  ϕ   ∘ ∂a(S) → A ∨ ϕ → A
+            return _or(A, derv(s)) if nully(r) else A
 
-        # ∂a(R ∧ S) → ∂a(R) ∧ ∂a(S)
-        # ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S)
-        dr, ds = derv(r), derv(s)
-        return _and(dr, ds) if tag == AND else _or(dr, ds)
+        # ∂a(R ∧ S) → ∂a(R) ∧ ∂a(S)
+        # ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S)
+        dr, ds = derv(r), derv(s)
+        return _and(dr, ds) if tag == AND else _or(dr, ds)
 
-    return derv
+    return derv
 
@@ -395,26 +395,26 @@ expressions from growing too large.

Let’s try it out…¶

(FIXME: redo.)

-
o, z = D_compaction('0'), D_compaction('1')
-REs = set()
-N = 5
-names = list(product(*(N * [(0, 1)])))
-dervs = list(product(*(N * [(o, z)])))
-for name, ds in zip(names, dervs):
-    R = it
-    ds = list(ds)
-    while ds:
-        R = ds.pop()(R)
-        if R == phi or R == I:
-            break
-        REs.add(R)
-
-print stringy(it) ; print
-print o.hits, '/', o.calls
-print z.hits, '/', z.calls
-print
-for s in sorted(map(stringy, REs), key=lambda n: (len(n), n)):
-    print s
+
o, z = D_compaction('0'), D_compaction('1')
+REs = set()
+N = 5
+names = list(product(*(N * [(0, 1)])))
+dervs = list(product(*(N * [(o, z)])))
+for name, ds in zip(names, dervs):
+    R = it
+    ds = list(ds)
+    while ds:
+        R = ds.pop()(R)
+        if R == phi or R == I:
+            break
+        REs.add(R)
+
+print stringy(it) ; print
+print o.hits, '/', o.calls
+print z.hits, '/', z.calls
+print
+for s in sorted(map(stringy, REs), key=lambda n: (len(n), n)):
+    print s
 
(.111.) & ((.01 | 11*)')
@@ -555,45 +555,45 @@ a --1--> ∂1(a)
 

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.

-
from collections import defaultdict
-from pprint import pprint
-from string import ascii_lowercase
+
from collections import defaultdict
+from pprint import pprint
+from string import ascii_lowercase
 
-
d0, d1 = D_compaction('0'), D_compaction('1')
+
d0, d1 = D_compaction('0'), D_compaction('1')
 

explore()¶

-
def explore(re):
+
def explore(re):
 
-    # Don't have more than 26 states...
-    names = defaultdict(iter(ascii_lowercase).next)
+    # Don't have more than 26 states...
+    names = defaultdict(iter(ascii_lowercase).next)
 
-    table, accepting = dict(), set()
+    table, accepting = dict(), set()
 
-    to_check = {re}
-    while to_check:
+    to_check = {re}
+    while to_check:
 
-        re = to_check.pop()
-        state_name = names[re]
+        re = to_check.pop()
+        state_name = names[re]
 
-        if (state_name, 0) in table:
-            continue
+        if (state_name, 0) in table:
+            continue
 
-        if nully(re):
-            accepting.add(state_name)
+        if nully(re):
+            accepting.add(state_name)
 
-        o, i = d0(re), d1(re)
-        table[state_name, 0] = names[o] ; to_check.add(o)
-        table[state_name, 1] = names[i] ; to_check.add(i)
+        o, i = d0(re), d1(re)
+        table[state_name, 0] = names[o] ; to_check.add(o)
+        table[state_name, 1] = names[i] ; to_check.add(i)
 
-    return table, accepting
+    return table, accepting
 
-
table, accepting = explore(it)
-table
+
table, accepting = explore(it)
+table
 
{('a', 0): 'b',
@@ -618,7 +618,7 @@ table
  ('j', 1): 'h'}
 
-
accepting
+
accepting
 
{'h', 'i'}
@@ -629,31 +629,31 @@ table
 

Generate Diagram¶

Once we have the FSM table and the set of accepting states we can generate the diagram above.

-
_template = '''\
-digraph finite_state_machine {
-  rankdir=LR;
-  size="8,5"
-  node [shape = doublecircle]; %s;
-  node [shape = circle];
-%s
-}
-'''
+
_template = '''\
+digraph finite_state_machine {
+  rankdir=LR;
+  size="8,5"
+  node [shape = doublecircle]; %s;
+  node [shape = circle];
+%s
+}
+'''
 
-def link(fr, nm, label):
-    return '  %s -> %s [ label = "%s" ];' % (fr, nm, label)
+def link(fr, nm, label):
+    return '  %s -> %s [ label = "%s" ];' % (fr, nm, label)
 
 
-def make_graph(table, accepting):
-    return _template % (
-        ' '.join(accepting),
-        '\n'.join(
-          link(from_, to, char)
-          for (from_, char), (to) in sorted(table.iteritems())
-          )
-        )
+def make_graph(table, accepting):
+    return _template % (
+        ' '.join(accepting),
+        '\n'.join(
+          link(from_, to, char)
+          for (from_, char), (to) in sorted(table.iteritems())
+          )
+        )
 
-
print make_graph(table, accepting)
+
print make_graph(table, accepting)
 
digraph finite_state_machine {
@@ -699,14 +699,14 @@ hard-code the information in the table into a little patch of branches.

Trampoline Function¶

Python has no GOTO statement but we can fake it with a “trampoline” function.

-
def trampoline(input_, jump_from, accepting):
-    I = iter(input_)
-    while True:
-        try:
-            bounce_to = jump_from(I)
-        except StopIteration:
-            return jump_from in accepting
-        jump_from = bounce_to
+
def trampoline(input_, jump_from, accepting):
+    I = iter(input_)
+    while True:
+        try:
+            bounce_to = jump_from(I)
+        except StopIteration:
+            return jump_from in accepting
+        jump_from = bounce_to
 
@@ -714,17 +714,17 @@ function.

Stream Functions¶

Little helpers to process the iterator of our data (a “stream” of “1” and “0” characters, not bits.)

-
getch = lambda I: int(next(I))
+
getch = lambda I: int(next(I))
 
 
-def _1(I):
-    '''Loop on ones.'''
-    while getch(I): pass
+def _1(I):
+    '''Loop on ones.'''
+    while getch(I): pass
 
 
-def _0(I):
-    '''Loop on zeros.'''
-    while not getch(I): pass
+def _0(I):
+    '''Loop on zeros.'''
+    while not getch(I): pass
 
@@ -735,28 +735,28 @@ def _0(I): 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.)

-
a = lambda I: c if getch(I) else b
-b = lambda I: _0(I) or d
-c = lambda I: e if getch(I) else b
-d = lambda I: f if getch(I) else b
-e = lambda I: g if getch(I) else b
-f = lambda I: h if getch(I) else b
-g = lambda I: _1(I) or i
-h = lambda I: _1(I) or i
-i = lambda I: _0(I) or j
-j = lambda I: h if getch(I) else i
+
a = lambda I: c if getch(I) else b
+b = lambda I: _0(I) or d
+c = lambda I: e if getch(I) else b
+d = lambda I: f if getch(I) else b
+e = lambda I: g if getch(I) else b
+f = lambda I: h if getch(I) else b
+g = lambda I: _1(I) or i
+h = lambda I: _1(I) or i
+i = lambda I: _0(I) or j
+j = lambda I: h if getch(I) else i
 

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.

-
def acceptable(input_):
-    return trampoline(input_, a, {h, i})
+
def acceptable(input_):
+    return trampoline(input_, a, {h, i})
 
-
for n in range(2**5):
-    s = bin(n)[2:]
-    print '%05s' % s, acceptable(s)
+
for n in range(2**5):
+    s = bin(n)[2:]
+    print '%05s' % s, acceptable(s)
 
    0 False
diff --git a/docs/sphinx_docs/_build/html/notebooks/Developing.html b/docs/sphinx_docs/_build/html/notebooks/Developing.html
index b670664..164db0d 100644
--- a/docs/sphinx_docs/_build/html/notebooks/Developing.html
+++ b/docs/sphinx_docs/_build/html/notebooks/Developing.html
@@ -43,17 +43,17 @@
 

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.

-
from notebook_preamble import J, V, define
+
from notebook_preamble import J, V, define
 

Sum a range filtered by a predicate¶

Let’s create a predicate that returns True if a number is a multiple of 3 or 5 and False otherwise.

-
define('P == [3 % not] dupdip 5 % not or')
+
define('P == [3 % not] dupdip 5 % not or')
 
-
V('80 P')
+
V('80 P')
 
             . 80 P
@@ -116,10 +116,10 @@ the counter to the running sum. This function will do that:

PE1.1 == + [+] dupdip
 
-
define('PE1.1 == + [+] dupdip')
+
define('PE1.1 == + [+] dupdip')
 
-
V('0 0 3 PE1.1')
+
V('0 0 3 PE1.1')
 
        . 0 0 3 PE1.1
@@ -134,7 +134,7 @@ the counter to the running sum. This function will do that:

3 3 .
-
V('0 0 [3 2 1 3 1 2 3] [PE1.1] step')
+
V('0 0 [3 2 1 3 1 2 3] [PE1.1] step')
 
                            . 0 0 [3 2 1 3 1 2 3] [PE1.1] step
@@ -217,26 +217,26 @@ total to 60.

How many multiples to sum?¶

-
1000 / 15
+
1000 / 15
 
66
 
-
66 * 15
+
66 * 15
 
990
 
-
1000 - 990
+
1000 - 990
 
10
 

We only want the terms less than 1000.

-
999 - 990
+
999 - 990
 
9
@@ -244,10 +244,10 @@ total to 60.

That means we want to run the full list of numbers sixty-six times to get to 990 and then the first four numbers 3 2 1 3 to get to 999.

-
define('PE1 == 0 0 66 [[3 2 1 3 1 2 3] [PE1.1] step] times [3 2 1 3] [PE1.1] step pop')
+
define('PE1 == 0 0 66 [[3 2 1 3 1 2 3] [PE1.1] step] times [3 2 1 3] [PE1.1] step pop')
 
-
J('PE1')
+
J('PE1')
 
233168
@@ -267,16 +267,16 @@ integer terms from the list.

0b 11 10 01 11 01 10 11 == 14811
-
0b11100111011011
+
0b11100111011011
 
14811
 
-
define('PE1.2 == [3 & PE1.1] dupdip 2 >>')
+
define('PE1.2 == [3 & PE1.1] dupdip 2 >>')
 
-
V('0 0 14811 PE1.2')
+
V('0 0 14811 PE1.2')
 
                      . 0 0 14811 PE1.2
@@ -299,7 +299,7 @@ integer terms from the list.

3 3 3702 .
-
V('3 3 3702 PE1.2')
+
V('3 3 3702 PE1.2')
 
                     . 3 3 3702 PE1.2
@@ -322,7 +322,7 @@ integer terms from the list.

8 5 925 .
-
V('0 0 14811 7 [PE1.2] times pop')
+
V('0 0 14811 7 [PE1.2] times pop')
 
                      . 0 0 14811 7 [PE1.2] times pop
@@ -459,10 +459,10 @@ integer terms from the list.

And so we have at last:

-
define('PE1 == 0 0 66 [14811 7 [PE1.2] times pop] times 14811 4 [PE1.2] times popop')
+
define('PE1 == 0 0 66 [14811 7 [PE1.2] times pop] times 14811 4 [PE1.2] times popop')
 
-
J('PE1')
+
J('PE1')
 
233168
@@ -477,14 +477,14 @@ integer terms from the list.

n 14811 swap [PE1.2] times pop
-
define('PE1.3 == 14811 swap [PE1.2] times pop')
+
define('PE1.3 == 14811 swap [PE1.2] times pop')
 

Now we can simplify the definition above:

-
define('PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop')
+
define('PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop')
 
-
J('PE1')
+
J('PE1')
 
233168
@@ -507,10 +507,10 @@ I hope it’s clear.

then four more. In the Generator Programs notebook we derive a generator that can be repeatedly driven by the x combinator to produce a stream of the seven numbers repeating over and over again.

-
define('PE1.terms == [0 swap [dup [pop 14811] [] branch [3 &] dupdip 2 >>] dip rest cons]')
+
define('PE1.terms == [0 swap [dup [pop 14811] [] branch [3 &] dupdip 2 >>] dip rest cons]')
 
-
J('PE1.terms 21 [x] times')
+
J('PE1.terms 21 [x] times')
 
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 [0 swap [dup [pop 14811] [] branch [3 &] dupdip 2 >>] dip rest cons]
@@ -518,19 +518,19 @@ produce a stream of the seven numbers repeating over and over again.

We know from above that we need sixty-six times seven then four more terms to reach up to but not over one thousand.

-
J('7 66 * 4 +')
+
J('7 66 * 4 +')
 
466
 
-
J('PE1.terms 466 [x] times pop')
+
J('PE1.terms 466 [x] times pop')
 
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3
 
-
J('[PE1.terms 466 [x] times pop] run sum')
+
J('[PE1.terms 466 [x] times pop] run sum')
 
999
@@ -539,7 +539,7 @@ terms to reach up to but not over one thousand.

Now we can use PE1.1 to accumulate the terms as we go, and then pop the generator and the counter from the stack when we’re done, leaving just the sum.

-
J('0 0 PE1.terms 466 [x [PE1.1] dip] times popop')
+
J('0 0 PE1.terms 466 [x [PE1.1] dip] times popop')
 
233168
@@ -550,7 +550,7 @@ leaving just the sum.

A little further analysis renders iteration unnecessary.¶

Consider finding the sum of the positive integers less than or equal to ten.

-
J('[10 9 8 7 6 5 4 3 2 1] sum')
+
J('[10 9 8 7 6 5 4 3 2 1] sum')
 
55
@@ -573,10 +573,10 @@ positive integers is:

(The formula also works for odd values of N, I’ll leave that to you if you want to work it out or you can take my word for it.)

-
define('F == dup ++ * 2 floordiv')
+
define('F == dup ++ * 2 floordiv')
 
-
V('10 F')
+
V('10 F')
 
      . 10 F
@@ -600,13 +600,13 @@ each, starting with:

If we reverse one of these two blocks and sum pairs…

-
J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip')
+
J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip')
 
[[978 15] [980 12] [981 10] [984 9] [985 6] [987 5] [990 3]]
 
-
J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map')
+
J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map')
 
[993 992 991 993 991 992 993]
@@ -614,7 +614,7 @@ each, starting with:

(Interesting that the sequence of seven numbers appears again in the rightmost digit of each term.)

-
J('[ 3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map sum')
+
J('[ 3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map sum')
 
6945
@@ -628,7 +628,7 @@ additional unpaired terms between 990 and 1000:

So we can give the “sum of all the multiples of 3 or 5 below 1000” like so:

-
J('6945 33 * [993 995 996 999] cons sum')
+
J('6945 33 * [993 995 996 999] cons sum')
 
233168
diff --git a/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html b/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html
index fe9f8b9..19aa59b 100644
--- a/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html
+++ b/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html
@@ -36,7 +36,7 @@
   

Using x to Generate Values¶

Cf. jp-reprod.html

-
from notebook_preamble import J, V, define
+
from notebook_preamble import J, V, define
 

Consider the x combinator:

@@ -76,7 +76,7 @@ function C

Let’s try it:

-
V('[0 swap [dup ++] dip rest cons] x')
+
V('[0 swap [dup ++] dip rest cons] x')
 
                                           . [0 swap [dup ++] dip rest cons] x
@@ -95,7 +95,7 @@ function C
 

After one application of x the quoted program contains 1 and 0 is below it on the stack.

-
J('[0 swap [dup ++] dip rest cons] x x x x x pop')
+
J('[0 swap [dup ++] dip rest cons] x x x x x pop')
 
0 1 2 3 4
@@ -103,10 +103,10 @@ function C
 

direco¶

-
define('direco == dip rest cons')
+
define('direco == dip rest cons')
 
-
V('[0 swap [dup ++] direco] x')
+
V('[0 swap [dup ++] direco] x')
 
                                    . [0 swap [dup ++] direco] x
@@ -147,17 +147,17 @@ our quoted program:

G == [direco] cons [swap] swoncat cons
-
define('G == [direco] cons [swap] swoncat cons')
+
define('G == [direco] cons [swap] swoncat cons')
 

Let’s try it out:

-
J('0 [dup ++] G')
+
J('0 [dup ++] G')
 
[0 swap [dup ++] direco]
 
-
J('0 [dup ++] G x x x pop')
+
J('0 [dup ++] G x x x pop')
 
0 1 2
@@ -165,7 +165,7 @@ our quoted program:

Powers of 2¶

-
J('1 [dup 1 <<] G x x x x x x x x x pop')
+
J('1 [dup 1 <<] G x x x x x x x x x pop')
 
1 2 4 8 16 32 64 128 256
@@ -176,7 +176,7 @@ our quoted program:

[x] times¶

If we have one of these quoted programs we can drive it using times with the x combinator.

-
J('23 [dup ++] G 5 [x] times')
+
J('23 [dup ++] G 5 [x] times')
 
23 24 25 26 27 [28 swap [dup ++] direco]
@@ -200,10 +200,10 @@ int:

And pick them off by masking with 3 (binary 11) and then shifting the int right two bits.

-
define('PE1.1 == dup [3 &] dip 2 >>')
+
define('PE1.1 == dup [3 &] dip 2 >>')
 
-
V('14811 PE1.1')
+
V('14811 PE1.1')
 
                  . 14811 PE1.1
@@ -220,14 +220,14 @@ int right two bits.

If we plug 14811 and [PE1.1] into our generator form…

-
J('14811 [PE1.1] G')
+
J('14811 [PE1.1] G')
 
[14811 swap [PE1.1] direco]
 

…we get a generator that works for seven cycles before it reaches zero:

-
J('[14811 swap [PE1.1] direco] 7 [x] times')
+
J('[14811 swap [PE1.1] direco] 7 [x] times')
 
3 2 1 3 1 2 3 [0 swap [PE1.1] direco]
@@ -237,16 +237,16 @@ int right two bits.

Reset at Zero¶

We need a function that checks if the int has reached zero and resets it if so.

-
define('PE1.1.check == dup [pop 14811] [] branch')
+
define('PE1.1.check == dup [pop 14811] [] branch')
 
-
J('14811 [PE1.1.check PE1.1] G')
+
J('14811 [PE1.1.check PE1.1] G')
 
[14811 swap [PE1.1.check PE1.1] direco]
 
-
J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
+
J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')
 
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 [0 swap [PE1.1.check PE1.1] direco]
@@ -262,20 +262,20 @@ say.)

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.

-
J('7 66 * 4 +')
+
J('7 66 * 4 +')
 
466
 

If we drive our generator 466 times and sum the stack we get 999.

-
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times')
+
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times')
 
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 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]
 
-
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum')
+
J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum')
 
999
@@ -285,11 +285,11 @@ numbers sixty-six times and then four more.

Project Euler Problem One¶

-
define('PE1.2 == + dup [+] dip')
+
define('PE1.2 == + dup [+] dip')
 

Now we can add PE1.2 to the quoted program given to G.

-
J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop')
+
J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop')
 
233168
@@ -351,13 +351,13 @@ numbers sixty-six times and then four more.

fib_gen == [1 1 F]
-
define('fib == + [popdd over] cons infra uncons')
+
define('fib == + [popdd over] cons infra uncons')
 
-
define('fib_gen == [1 1 fib]')
+
define('fib_gen == [1 1 fib]')
 
-
J('fib_gen 10 [x] times')
+
J('fib_gen 10 [x] times')
 
1 2 3 5 8 13 21 34 55 89 [144 89 fib]
@@ -373,21 +373,21 @@ not exceed four million, find the sum of the even-valued terms.

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 pops it otherwise.

-
define('PE2.1 == dup 2 % [+] [pop] branch')
+
define('PE2.1 == dup 2 % [+] [pop] branch')
 

And a predicate function that detects when the terms in the series “exceed four million”.

-
define('>4M == 4000000 >')
+
define('>4M == 4000000 >')
 

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.

-
define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec')
+
define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec')
 
-
J('PE2')
+
J('PE2')
 
4613732
@@ -418,23 +418,23 @@ and sums the even ones.

Every third term is even.

-
J('[1 0 fib] x x x')  # To start the sequence with 1 1 2 3 instead of 1 2 3.
+
J('[1 0 fib] x x x')  # To start the sequence with 1 1 2 3 instead of 1 2 3.
 
1 1 2 [3 2 fib]
 

Drive the generator three times and popop the two odd terms.

-
J('[1 0 fib] x x x [popop] dipd')
+
J('[1 0 fib] x x x [popop] dipd')
 
2 [3 2 fib]
 
-
define('PE2.2 == x x x [popop] dipd')
+
define('PE2.2 == x x x [popop] dipd')
 
-
J('[1 0 fib] 10 [PE2.2] times')
+
J('[1 0 fib] 10 [PE2.2] times')
 
2 8 34 144 610 2584 10946 46368 196418 832040 [1346269 832040 fib]
@@ -442,7 +442,7 @@ and sums the even ones.

Replace x with our new driver function PE2.2 and start our fib generator at 1 0.

-
J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec')
+
J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec')
 
4613732
@@ -457,10 +457,10 @@ modifications to the default 
 

An Interesting Variation¶

-
define('codireco == cons dip rest cons')
+
define('codireco == cons dip rest cons')
 
-
V('[0 [dup ++] codireco] x')
+
V('[0 [dup ++] codireco] x')
 
                                 . [0 [dup ++] codireco] x
@@ -479,10 +479,10 @@ modifications to the default 0 [1 [dup ++] codireco] .
 
-
define('G == [codireco] cons cons')
+
define('G == [codireco] cons cons')
 
-
J('230 [dup ++] G 5 [x] times pop')
+
J('230 [dup ++] G 5 [x] times pop')
 
230 231 232 233 234
diff --git a/docs/sphinx_docs/_build/html/notebooks/Intro.html b/docs/sphinx_docs/_build/html/notebooks/Intro.html
index bf30d3b..658704d 100644
--- a/docs/sphinx_docs/_build/html/notebooks/Intro.html
+++ b/docs/sphinx_docs/_build/html/notebooks/Intro.html
@@ -157,33 +157,33 @@ like that.

Examples¶

-
joy.parser.text_to_expression('1 2 3 4 5')  # A simple sequence.
+
joy.parser.text_to_expression('1 2 3 4 5')  # A simple sequence.
 
(1, (2, (3, (4, (5, ())))))
 
-
joy.parser.text_to_expression('[1 2 3] 4 5')  # Three items, the first is a list with three items
+
joy.parser.text_to_expression('[1 2 3] 4 5')  # Three items, the first is a list with three items
 
((1, (2, (3, ()))), (4, (5, ())))
 
-
joy.parser.text_to_expression('1 23 ["four" [-5.0] cons] 8888')  # A mixed bag. cons is
-                                                                 # a Symbol, no lookup at
-                                                                 # parse-time.  Haiku docs.
+
joy.parser.text_to_expression('1 23 ["four" [-5.0] cons] 8888')  # A mixed bag. cons is
+                                                                 # a Symbol, no lookup at
+                                                                 # parse-time.  Haiku docs.
 
(1, (23, (('four', ((-5.0, ()), (cons, ()))), (8888, ()))))
 
-
joy.parser.text_to_expression('[][][][][]')  # Five empty lists.
+
joy.parser.text_to_expression('[][][][][]')  # Five empty lists.
 
((), ((), ((), ((), ((), ())))))
 
-
joy.parser.text_to_expression('[[[[[]]]]]')  # Five nested lists.
+
joy.parser.text_to_expression('[[[[[]]]]]')  # Five nested lists.
 
((((((), ()), ()), ()), ()), ())
@@ -199,7 +199,7 @@ the Joy system. There are simple functions such as addition +, the library module supports aliases), and combinators which
 provide control-flow and higher-order operations.

Many of the functions are defined in Python, like dip:

-
print inspect.getsource(joy.library.dip)
+
print inspect.getsource(joy.library.dip)
 
def dip(stack, expression, dictionary):
@@ -212,7 +212,7 @@ provide control-flow and higher-order operations.

When the interpreter executes a definition function that function just pushes its body expression onto the pending expression (the continuation) and returns control to the interpreter.

-
print joy.library.definitions
+
print joy.library.definitions
 
second == rest first
diff --git a/docs/sphinx_docs/_build/html/notebooks/Ordered_Binary_Trees.html b/docs/sphinx_docs/_build/html/notebooks/Ordered_Binary_Trees.html
index 6665db0..eabfaba 100644
--- a/docs/sphinx_docs/_build/html/notebooks/Ordered_Binary_Trees.html
+++ b/docs/sphinx_docs/_build/html/notebooks/Ordered_Binary_Trees.html
@@ -63,7 +63,7 @@ the Sufficiently Smart Compiler can be modified to use an optimized
 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.)

-
from notebook_preamble import D, J, V, define, DefinitionWrapper
+
from notebook_preamble import D, J, V, define, DefinitionWrapper
 
@@ -100,10 +100,10 @@ functions on otherwise undistinguished Joy datastructures.)

Tree-new == swap [[] []] cons cons
 
-
define('Tree-new == swap [[] []] cons cons')
+
define('Tree-new == swap [[] []] cons cons')
 
-
J('"v" "k" Tree-new')
+
J('"v" "k" Tree-new')
 
['k' 'v' [] []]
@@ -159,10 +159,10 @@ comparison operator:

P == pop roll> pop first
-
define('P == pop roll> pop first')
+
define('P == pop roll> pop first')
 
-
J('["old_key" 23 [] []] 17 "new_key" ["..."] P')
+
J('["old_key" 23 [] []] 17 "new_key" ["..."] P')
 
'new_key' 'old_key'
@@ -217,10 +217,10 @@ stack:

T == cons cons [dipdd] cons infra
 
-
define('T == cons cons [dipdd] cons infra')
+
define('T == cons cons [dipdd] cons infra')
 
-
J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T')
+
J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T')
 
['old_k' 'old_value' 'left' 'Tree-add' 'new_key' 'new_value' 'right']
@@ -234,7 +234,7 @@ stack:

[key_n value_n left right] value key [Tree-add] [P <] [Te] [Ee] ifte
-
define('E == [P <] [Te] [Ee] ifte')
+
define('E == [P <] [Te] [Ee] ifte')
 

In this case Te works that same as T but on the left child tree @@ -243,10 +243,10 @@ instead of the right, so the only difference is that it must use

Te == cons cons [dipd] cons infra
 
-
define('Te == cons cons [dipd] cons infra')
+
define('Te == cons cons [dipd] cons infra')
 
-
J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te')
+
J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te')
 
['old_k' 'old_value' 'Tree-add' 'new_key' 'new_value' 'left' 'right']
@@ -274,10 +274,10 @@ instead of the right, so the only difference is that it must use
               [key new_value left right]
 
-
define('Ee == pop swap roll< rest rest cons cons')
+
define('Ee == pop swap roll< rest rest cons cons')
 
-
J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee')
+
J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee')
 
['k' 'new_value' 'left' 'right']
@@ -302,43 +302,43 @@ instead of the right, so the only difference is that it must use
 Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec
 
-
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec')
+
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec')
 

Examples¶

-
J('[] 23 "b" Tree-add')  # Initial
+
J('[] 23 "b" Tree-add')  # Initial
 
['b' 23 [] []]
 
-
J('["b" 23 [] []] 88 "c" Tree-add')  # Greater than
+
J('["b" 23 [] []] 88 "c" Tree-add')  # Greater than
 
['b' 23 [] ['c' 88 [] []]]
 
-
J('["b" 23 [] []] 88 "a" Tree-add')  # Less than
+
J('["b" 23 [] []] 88 "a" Tree-add')  # Less than
 
['b' 23 ['a' 88 [] []] []]
 
-
J('["b" 23 [] []] 88 "b" Tree-add')  # Equal to
+
J('["b" 23 [] []] 88 "b" Tree-add')  # Equal to
 
['b' 88 [] []]
 
-
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add')  # Series.
+
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add')  # Series.
 
['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
 
-
J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step')
+
J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step')
 
['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
@@ -365,19 +365,19 @@ values:

L
-
J("1 0 ['G'] ['E'] ['L'] cmp")
+
J("1 0 ['G'] ['E'] ['L'] cmp")
 
'G'
 
-
J("1 1 ['G'] ['E'] ['L'] cmp")
+
J("1 1 ['G'] ['E'] ['L'] cmp")
 
'E'
 
-
J("0 1 ['G'] ['E'] ['L'] cmp")
+
J("0 1 ['G'] ['E'] ['L'] cmp")
 
'L'
@@ -414,7 +414,7 @@ node key (by throwing everything else away):

P == over [popop popop first] nullary
 
-
define('P == over [popop popop first] nullary')
+
define('P == over [popop popop first] nullary')
 

Using cmp to simplify our code above at @@ -434,10 +434,10 @@ to understand:

Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec
 
-
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec')
+
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec')
 
-
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add')  # Still works.
+
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add')  # Still works.
 
['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
@@ -545,22 +545,22 @@ with an interesting situation:

Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec
 
-
define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec')
+
define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec')
 

Examples¶

-
J('[] [foo] Tree-iter')  #  It doesn't matter what F is as it won't be used.
+
J('[] [foo] Tree-iter')  #  It doesn't matter what F is as it won't be used.
 
-
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter")
+
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter")
 
'b' 'a' 'c'
 
-
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter")
+
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter")
 
23 88 44
@@ -575,16 +575,16 @@ to e.g. 0 and ignoring them. It’s set-like in that duplicate items added
 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.

-
J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step')
+
J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step')
 
[3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]]
 
-
define('to_set == [] swap [0 swap Tree-add] step')
+
define('to_set == [] swap [0 swap Tree-add] step')
 
-
J('[3 9 5 2 8 6 7 8 4] to_set')
+
J('[3 9 5 2 8 6 7 8 4] to_set')
 
[3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]]
@@ -592,10 +592,10 @@ time.

And with that we can write a little program unique to remove duplicate items from a list.

-
define('unique == [to_set [first] Tree-iter] cons run')
+
define('unique == [to_set [first] Tree-iter] cons run')
 
-
J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique')  # Filter duplicate items.
+
J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique')  # Filter duplicate items.
 
[7 6 8 4 5 9 2 3]
@@ -679,23 +679,23 @@ right side:

Now we can sort sequences.

-
#define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec')
+
#define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec')
 
 
-DefinitionWrapper.add_definitions('''
+DefinitionWrapper.add_definitions('''
 
-fourth == rest rest rest first
+fourth == rest rest rest first
 
-proc_left == [cons dip] dupdip
-proc_current == [[first] dupdip] dip
-proc_right == [fourth] dip i
+proc_left == [cons dip] dupdip
+proc_current == [[first] dupdip] dip
+proc_right == [fourth] dip i
 
-Tree-iter-order == [not] [pop] [dup third] [proc_left proc_current proc_right] genrec
+Tree-iter-order == [not] [pop] [dup third] [proc_left proc_current proc_right] genrec
 
-''', D)
+''', D)
 
-
J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order')
+
J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order')
 
2 3 4 5 6 7 8 9
@@ -835,54 +835,54 @@ because there’s no value to discard.

Tree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec
-
# 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
-# definitions that are only in scope for a given definition.  I don't want to implement
-# that (yet) so...
+
# 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
+# definitions that are only in scope for a given definition.  I don't want to implement
+# that (yet) so...
 
 
-define('''
-Tree-get == [pop not] swap [] [
-  over [pop popop first] nullary
-  [[fourth] dipd i]
-  [popop second]
-  [[third] dipd i]
-  cmp
-  ] genrec
-''')
+define('''
+Tree-get == [pop not] swap [] [
+  over [pop popop first] nullary
+  [[fourth] dipd i]
+  [popop second]
+  [[third] dipd i]
+  cmp
+  ] genrec
+''')
 
-
J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get')
+
J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get')
 
'mike not in tree'
 
-
J('["gary" 23 [] []] "gary" [popop "err"] Tree-get')
+
J('["gary" 23 [] []] "gary" [popop "err"] Tree-get')
 
23
 
-
J('''
+
J('''
 
-    [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step
+    [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step
 
-    'c' [popop 'not found'] Tree-get
+    'c' [popop 'not found'] Tree-get
 
-''')
+''')
 
2
 
-
J('''
+
J('''
 
-    [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step
+    [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step
 
-    'd' [popop 'not found'] Tree-get
+    'd' [popop 'not found'] Tree-get
 
-''')
+''')
 
'not found'
@@ -1175,61 +1175,61 @@ E == [
 

By the standards of the code I’ve written so far, this is a huge Joy program.

-
DefinitionWrapper.add_definitions('''
-first_two == uncons uncons pop
-fourth == rest rest rest first
-?fourth == [] [fourth] [] ifte
-W.rightmost == [?fourth] [fourth] while
-E.clear_stuff == roll> popop rest
-E.delete == cons dipd
-W == dup W.rightmost first_two over
-E.0 == E.clear_stuff [W] dip E.delete swap
-E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[E.0] cons infra]] cond
-T> == [dipd] cons infra
-T< == [dipdd] cons infra
-R0 == over first swap dup
-R1 == cons roll> [T>] [E] [T<] cmp
-Tree-Delete == [pop not] [pop] [R0] [R1] genrec
-''', D)
-
-
-
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ")
+
DefinitionWrapper.add_definitions('''
+first_two == uncons uncons pop
+fourth == rest rest rest first
+?fourth == [] [fourth] [] ifte
+W.rightmost == [?fourth] [fourth] while
+E.clear_stuff == roll> popop rest
+E.delete == cons dipd
+W == dup W.rightmost first_two over
+E.0 == E.clear_stuff [W] dip E.delete swap
+E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[E.0] cons infra]] cond
+T> == [dipd] cons infra
+T< == [dipdd] cons infra
+R0 == over first swap dup
+R1 == cons roll> [T>] [E] [T<] cmp
+Tree-Delete == [pop not] [pop] [R0] [R1] genrec
+''', D)
+
+
+
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ")
 
['a' 23 [] ['b' 88 [] []]]
 
-
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ")
+
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ")
 
['a' 23 [] ['c' 44 [] []]]
 
-
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ")
+
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ")
 
['b' 88 [] ['c' 44 [] []]]
 
-
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ")
+
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ")
 
['a' 23 [] ['b' 88 [] ['c' 44 [] []]]]
 
-
J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step')
+
J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step')
 
[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]]
 
-
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ")
+
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ")
 
[4 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]]
 
-
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ")
+
J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ")
 
[3 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]]
diff --git a/docs/sphinx_docs/_build/html/notebooks/Quadratic.html b/docs/sphinx_docs/_build/html/notebooks/Quadratic.html
index e617c60..40c3b6d 100644
--- a/docs/sphinx_docs/_build/html/notebooks/Quadratic.html
+++ b/docs/sphinx_docs/_build/html/notebooks/Quadratic.html
@@ -34,7 +34,7 @@
 
           
-
from notebook_preamble import J, V, define
+  
from notebook_preamble import J, V, define
 
@@ -100,11 +100,11 @@ 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:

-
define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
+
define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2')
 

Let’s try it out:

-
J('3 1 1 quadratic')
+
J('3 1 1 quadratic')
 
-0.3819660112501051 -2.618033988749895
@@ -114,7 +114,7 @@ the right and say it’s the definition of 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.

-
V('-5 1 4 quadratic')
+
V('-5 1 4 quadratic')
 
                                                   . -5 1 4 quadratic
diff --git a/docs/sphinx_docs/_build/html/notebooks/Recursion_Combinators.html b/docs/sphinx_docs/_build/html/notebooks/Recursion_Combinators.html
index f6a7fb3..5500e18 100644
--- a/docs/sphinx_docs/_build/html/notebooks/Recursion_Combinators.html
+++ b/docs/sphinx_docs/_build/html/notebooks/Recursion_Combinators.html
@@ -33,7 +33,7 @@
 
           
-
from notebook_preamble import D, DefinitionWrapper, J, V, define
+  
from notebook_preamble import D, DefinitionWrapper, J, V, define
 
@@ -101,18 +101,18 @@ cons list”.

It may be helpful to see this function implemented in imperative Python code.

-
def hylomorphism(c, F, P, G):
-    '''Return a hylomorphism function H.'''
+
def hylomorphism(c, F, P, G):
+    '''Return a hylomorphism function H.'''
 
-    def H(a):
-        if P(a):
-            result = c
-        else:
-            b, aa = G(a)
-            result = F(b, H(aa))  # b is stored in the stack frame during recursive call to H().
-        return result
+    def H(a):
+        if P(a):
+            result = c
+        else:
+            b, aa = G(a)
+            result = F(b, H(aa))  # b is stored in the stack frame during recursive call to H().
+        return result
 
-    return H
+    return H
 

Cf. “Bananas, Lenses, & Barbed @@ -185,7 +185,7 @@ the left so we have a definition for

-
define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')
+
define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')
 
@@ -200,17 +200,17 @@ of all positive integers less than that one. (In this case the types
  • [G] is [-- dup]

  • [F] is [+]

  • -
    define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
    +
    define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism')
     

    Let’s try it:

    -
    J('5 triangular_number')
    +
    J('5 triangular_number')
     
    10
     
    -
    J('[0 1 2 3 4 5 6] [triangular_number] map')
    +
    J('[0 1 2 3 4 5 6] [triangular_number] map')
     
    [0 0 1 3 6 10 15]
    @@ -372,10 +372,10 @@ values.

    == [0 <=] [pop []] [-- dup] [dip swons] genrec
    -
    define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
    +
    define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
     
    -
    J('5 range')
    +
    J('5 range')
     
    [4 3 2 1 0]
    @@ -388,10 +388,10 @@ values.

    == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
    -
    define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
    +
    define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
     
    -
    J('5 range_reverse')
    +
    J('5 range_reverse')
     
    [0 1 2 3 4]
    @@ -404,10 +404,10 @@ values.

    == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
    -
    define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
    +
    define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
     
    -
    J('5 ranger')
    +
    J('5 ranger')
     
    [5 4 3 2 1]
    @@ -420,10 +420,10 @@ values.

    == [] swap [0 <=] [pop] [[swons] dupdip --] primrec
    -
    define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
    +
    define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
     
    -
    J('5 ranger_reverse')
    +
    J('5 ranger_reverse')
     
    [1 2 3 4 5]
    @@ -444,17 +444,17 @@ and makes some new value.

    C == [not] c [uncons swap] [F] hylomorphism
     
    -
    define('swuncons == uncons swap')  # Awkward name.
    +
    define('swuncons == uncons swap')  # Awkward name.
     

    An example of a catamorphism is the sum function.

    sum == [not] 0 [swuncons] [+] hylomorphism
     
    -
    define('sum == [not] 0 [swuncons] [+] hylomorphism')
    +
    define('sum == [not] 0 [swuncons] [+] hylomorphism')
     
    -
    J('[5 4 3 2 1] sum')
    +
    J('[5 4 3 2 1] sum')
     
    15
    @@ -464,7 +464,7 @@ and makes some new value.

    The step combinator¶

    The step combinator will usually be better to use than catamorphism.

    -
    J('[step] help')
    +
    J('[step] help')
     
    Run a quoted program on each item in a sequence.
    @@ -488,10 +488,10 @@ and makes some new value.

    on top of the stack.
    -
    define('sum == 0 swap [+] step')
    +
    define('sum == 0 swap [+] step')
     
    -
    J('[5 4 3 2 1] sum')
    +
    J('[5 4 3 2 1] sum')
     
    15
    @@ -512,10 +512,10 @@ and makes some new value.

    P == 1 <=
    -
    define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
    +
    define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
     
    -
    J('5 factorial')
    +
    J('5 factorial')
     
    120
    @@ -544,10 +544,10 @@ pattern H2P == not
     
    -
    define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
    +
    define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
     
    -
    J('[1 2 3] tails')
    +
    J('[1 2 3] tails')
     
    [[] [3] [2 3]]
    diff --git a/docs/sphinx_docs/_build/html/notebooks/Replacing.html b/docs/sphinx_docs/_build/html/notebooks/Replacing.html
    index f152c0e..6f1aaf6 100644
    --- a/docs/sphinx_docs/_build/html/notebooks/Replacing.html
    +++ b/docs/sphinx_docs/_build/html/notebooks/Replacing.html
    @@ -42,12 +42,12 @@ we can implement e.g. a function that adds new functions to the
     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.

    -
    from notebook_preamble import D, J, V
    +
    from notebook_preamble import D, J, V
     

    A long trace¶

    -
    V('[23 18] average')
    +
    V('[23 18] average')
     
                                      . [23 18] average
    @@ -105,30 +105,30 @@ it in Python, not Joy.

    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.

    -
    from joy.library import SimpleFunctionWrapper
    -from joy.utils.stack import iter_stack
    +
    from joy.library import SimpleFunctionWrapper
    +from joy.utils.stack import iter_stack
     
     
    -@SimpleFunctionWrapper
    -def size(stack):
    -    '''Return the size of the sequence on the stack.'''
    -    sequence, stack = stack
    -    n = 0
    -    for _ in iter_stack(sequence):
    -        n += 1
    -    return n, stack
    +@SimpleFunctionWrapper
    +def size(stack):
    +    '''Return the size of the sequence on the stack.'''
    +    sequence, stack = stack
    +    n = 0
    +    for _ in iter_stack(sequence):
    +        n += 1
    +    return n, stack
     

    Now we replace the old version in the dictionary with the new version, and re-evaluate the expression.

    -
    D['size'] = size
    +
    D['size'] = size
     

    A shorter trace¶

    You can see that size now executes in a single step.

    -
    V('[23 18] average')
    +
    V('[23 18] average')
     
                                      . [23 18] average
    diff --git a/docs/sphinx_docs/_build/html/notebooks/Treestep.html b/docs/sphinx_docs/_build/html/notebooks/Treestep.html
    index a0903ee..91fea34 100644
    --- a/docs/sphinx_docs/_build/html/notebooks/Treestep.html
    +++ b/docs/sphinx_docs/_build/html/notebooks/Treestep.html
    @@ -148,17 +148,17 @@ the desired outcome.

    Define treestep¶

    -
    from notebook_preamble import D, J, V, define, DefinitionWrapper
    +
    from notebook_preamble import D, J, V, define, DefinitionWrapper
     
    -
    DefinitionWrapper.add_definitions('''
    +
    DefinitionWrapper.add_definitions('''
     
    -    _treestep_0 == [[not] swap] dip
    -    _treestep_1 == [dip] cons [uncons] swoncat
    -    treegrind == [_treestep_1 _treestep_0] dip genrec
    -    treestep == [map] swoncat treegrind
    +    _treestep_0 == [[not] swap] dip
    +    _treestep_1 == [dip] cons [uncons] swoncat
    +    treegrind == [_treestep_1 _treestep_0] dip genrec
    +    treestep == [map] swoncat treegrind
     
    -''', D)
    +''', D)
     
    @@ -169,7 +169,7 @@ all nodes in a tree with this function:

    sumtree == [pop 0] [] [sum +] treestep
     
    -
    define('sumtree == [pop 0] [] [sum +] treestep')
    +
    define('sumtree == [pop 0] [] [sum +] treestep')
     

    Running this function on an empty tree value gives zero:

    @@ -178,7 +178,7 @@ all nodes in a tree with this function:

    0
    -
    J('[] sumtree')  # Empty tree.
    +
    J('[] sumtree')  # Empty tree.
     
    0
    @@ -192,61 +192,61 @@ all nodes in a tree with this function:

    n+m
    -
    J('[23] sumtree')  # No child trees.
    +
    J('[23] sumtree')  # No child trees.
     
    23
     
    -
    J('[23 []] sumtree')  # Child tree, empty.
    +
    J('[23 []] sumtree')  # Child tree, empty.
     
    23
     
    -
    J('[23 [2 [4]] [3]] sumtree')  # Non-empty child trees.
    +
    J('[23 [2 [4]] [3]] sumtree')  # Non-empty child trees.
     
    32
     
    -
    J('[23 [2 [8] [9]] [3] [4 []]] sumtree')  # Etc...
    +
    J('[23 [2 [8] [9]] [3] [4 []]] sumtree')  # Etc...
     
    49
     
    -
    J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep')  # Alternate "spelling".
    +
    J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep')  # Alternate "spelling".
     
    49
     
    -
    J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep')  # Replace each node.
    +
    J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep')  # Replace each node.
     
    [23 [23 [23] [23]] [23] [23 []]]
     
    -
    J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep')
    +
    J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep')
     
    [1 [1 [1] [1]] [1] [1 []]]
     
    -
    J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree')
    +
    J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree')
     
    6
     
    -
    J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep')  # Combine replace and sum into one function.
    +
    J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep')  # Combine replace and sum into one function.
     
    6
     
    -
    J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep')  # Combine replace and sum into one function.
    +
    J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep')  # Combine replace and sum into one function.
     
    3
    @@ -277,7 +277,7 @@ all nodes in a tree with this function:

    This doesn’t quite work:

    -
    J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep')
    +
    J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep')
     
    3 'B' 'B'
    @@ -299,7 +299,7 @@ depositing our results directly on the stack.

    [] [first] [flatten cons] treestep
     
    -
    J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [] [first] [flatten cons] treestep')
    +
    J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [] [first] [flatten cons] treestep')
     
    [3 2 9 5 4 8 6 7]
    @@ -322,7 +322,7 @@ depositing our results directly on the stack.

    [] [i roll< swons concat] [first] treestep
     
    -
    J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [] [uncons pop] [i roll< swons concat] treestep')
    +
    J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [] [uncons pop] [i roll< swons concat] treestep')
     
    [2 3 4 5 6 7 8 9]
    @@ -343,7 +343,7 @@ non-empty node is:

    [key value] N [left right] [K] C
     
    -
    J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
    +
    J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
     
    ['key' 'value'] 'N' [['left'] ['right']] [[not] ['B'] [uncons ['N'] dip] ['C'] genrec] 'C'
    @@ -353,21 +353,21 @@ non-empty node is:

    treegrind with step¶

    Iteration through the nodes

    -
    J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [pop] ["N"] [step] treegrind')
    +
    J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [pop] ["N"] [step] treegrind')
     
    [3 0] 'N' [2 0] 'N' [9 0] 'N' [5 0] 'N' [4 0] 'N' [8 0] 'N' [6 0] 'N' [7 0] 'N'
     

    Sum the nodes’ keys.

    -
    J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [pop] [first +] [step] treegrind')
    +
    J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [pop] [first +] [step] treegrind')
     
    44
     

    Rebuild the tree using map (imitating treestep.)

    -
    J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [] [[100 +] infra] [map cons] treegrind')
    +
    J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]]   [] [[100 +] infra] [map cons] treegrind')
     
    [[103 0] [[102 0] [] []] [[109 0] [[105 0] [[104 0] [] []] [[108 0] [[106 0] [] [[107 0] [] []]] []]] []]]
    @@ -449,37 +449,37 @@ equal):

    To me, that seems simpler than the genrec version.

    -
    DefinitionWrapper.add_definitions('''
    +
    DefinitionWrapper.add_definitions('''
     
    -    T> == pop [first] dip i
    -    T< == pop [second] dip i
    -    E == roll> popop first
    -    P == roll< [roll< uncons swap] dip
    +    T> == pop [first] dip i
    +    T< == pop [second] dip i
    +    E == roll> popop first
    +    P == roll< [roll< uncons swap] dip
     
    -    Tree-get == [P [T>] [E] [T<] cmp] treegrind
    +    Tree-get == [P [T>] [E] [T<] cmp] treegrind
     
    -''', D)
    +''', D)
     
    -
    J('''\
    +
    J('''\
     
    -[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
    +[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
     
    -[] [5] Tree-get
    +[] [5] Tree-get
     
    -''')
    +''')
     
    15
     
    -
    J('''\
    +
    J('''\
     
    -[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
    +[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
     
    -[pop "nope"] [25] Tree-get
    +[pop "nope"] [25] Tree-get
     
    -''')
    +''')
     
    'nope'
    diff --git a/docs/sphinx_docs/_build/html/notebooks/TypeChecking.html b/docs/sphinx_docs/_build/html/notebooks/TypeChecking.html
    index 9c4d5bb..6e5002d 100644
    --- a/docs/sphinx_docs/_build/html/notebooks/TypeChecking.html
    +++ b/docs/sphinx_docs/_build/html/notebooks/TypeChecking.html
    @@ -35,33 +35,33 @@
                 
       

    Type Checking¶

    -
    import logging, sys
    +
    import logging, sys
     
    -logging.basicConfig(
    -  format='%(message)s',
    -  stream=sys.stdout,
    -  level=logging.INFO,
    -  )
    +logging.basicConfig(
    +  format='%(message)s',
    +  stream=sys.stdout,
    +  level=logging.INFO,
    +  )
     
    -
    from joy.utils.types import (
    -    doc_from_stack_effect,
    -    infer,
    -    reify,
    -    unify,
    -    FUNCTIONS,
    -    JoyTypeError,
    -)
    +
    from joy.utils.types import (
    +    doc_from_stack_effect,
    +    infer,
    +    reify,
    +    unify,
    +    FUNCTIONS,
    +    JoyTypeError,
    +)
     
    -
    D = FUNCTIONS.copy()
    -del D['product']
    -globals().update(D)
    +
    D = FUNCTIONS.copy()
    +del D['product']
    +globals().update(D)
     

    An Example¶

    -
    fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0]
    +
    fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0]
     
    25 (--) ∘ pop swap rolldown rrest ccons
    @@ -72,32 +72,32 @@ globals().update(D)
     40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘
     
    -
    print doc_from_stack_effect(fi, fo)
    +
    print doc_from_stack_effect(fi, fo)
     
    ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
     
    -
    from joy.parser import text_to_expression
    -from joy.utils.stack import stack_to_string
    +
    from joy.parser import text_to_expression
    +from joy.utils.stack import stack_to_string
     
    -
    e = text_to_expression('0 1 2 [3 4]')  # reverse order
    -print stack_to_string(e)
    +
    e = text_to_expression('0 1 2 [3 4]')  # reverse order
    +print stack_to_string(e)
     
    [3 4] 2 1 0
     
    -
    u = unify(e, fi)[0]
    -u
    +
    u = unify(e, fi)[0]
    +u
     
    {a1: 0, a2: 1, a3: 2, a4: 3, a5: 4, s2: (), s1: ()}
     
    -
    g = reify(u, (fi, fo))
    -print doc_from_stack_effect(*g)
    +
    g = reify(u, (fi, fo))
    +print doc_from_stack_effect(*g)
     
    (... [3 4 ] 2 1 0 -- ... [1 2 ])
    @@ -106,18 +106,18 @@ print doc_from_stack_effect(*g)
     

    Unification Works “in Reverse”¶

    -
    e = text_to_expression('[2 3]')
    +
    e = text_to_expression('[2 3]')
     
    -
    u = unify(e, fo)[0]  # output side, not input side
    -u
    +
    u = unify(e, fo)[0]  # output side, not input side
    +u
     
    {a2: 2, a3: 3, s2: (), s1: ()}
     
    -
    g = reify(u, (fi, fo))
    -print doc_from_stack_effect(*g)
    +
    g = reify(u, (fi, fo))
    +print doc_from_stack_effect(*g)
     
    (... [a4 a5 ] 3 2 a1 -- ... [2 3 ])
    @@ -126,7 +126,7 @@ print doc_from_stack_effect(*g)
     

    Failing a Check¶

    -
    fi, fo = infer(dup, mul)[0]
    +
    fi, fo = infer(dup, mul)[0]
     
    25 (--) ∘ dup mul
    @@ -135,17 +135,17 @@ print doc_from_stack_effect(*g)
     31 (i1 -- i2) ∘
     
    -
    e = text_to_expression('"two"')
    -print stack_to_string(e)
    +
    e = text_to_expression('"two"')
    +print stack_to_string(e)
     
    'two'
     
    -
    try:
    -    unify(e, fi)
    -except JoyTypeError, err:
    -    print err
    +
    try:
    +    unify(e, fi)
    +except JoyTypeError, err:
    +    print err
     
    Cannot unify 'two' and f1.
    diff --git a/docs/sphinx_docs/_build/html/notebooks/Types.html b/docs/sphinx_docs/_build/html/notebooks/Types.html
    index 695d853..92d9131 100644
    --- a/docs/sphinx_docs/_build/html/notebooks/Types.html
    +++ b/docs/sphinx_docs/_build/html/notebooks/Types.html
    @@ -182,8 +182,8 @@ terms in the forms:

    Compiling pop∘swap∘roll<¶

    The simplest way to “compile” this function would be something like:

    -
    def poswrd(s, e, d):
    -    return rolldown(*swap(*pop(s, e, d)))
    +
    def poswrd(s, e, d):
    +    return rolldown(*swap(*pop(s, e, d)))
     

    However, internally this function would still be allocating tuples @@ -193,9 +193,9 @@ terms in the forms:

    We should be able to directly write out a Python function like:

    -
    def poswrd(stack):
    -    (_, (a, (b, (c, stack)))) = stack
    -    return (c, (b, (a, stack)))
    +
    def poswrd(stack):
    +    (_, (a, (b, (c, stack)))) = stack
    +    return (c, (b, (a, stack)))
     

    This eliminates the internal work of the first version. Because this @@ -335,9 +335,9 @@ actually pretty easy. I’ll explain below.

    From this stack effect comment it should be possible to construct the following Python code:

    -
    def F(stack):
    -    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
    -    return (d, (c, S0)), stack
    +
    def F(stack):
    +    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
    +    return (d, (c, S0)), stack
     
    @@ -348,96 +348,96 @@ following Python code:

    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:

    -
    roll_dn = (1, 2, 3), (2, 3, 1)
    +
    roll_dn = (1, 2, 3), (2, 3, 1)
     
    -pop = (1,), ()
    +pop = (1,), ()
     
    -swap = (1, 2), (2, 1)
    +swap = (1, 2), (2, 1)
     

    compose()¶

    -
    def compose(f, g):
    +
    def compose(f, g):
     
    -    (f_in, f_out), (g_in, g_out) = f, g
    +    (f_in, f_out), (g_in, g_out) = f, g
     
    -    # First rule.
    -    #
    -    #       (a -- b) (-- d)
    -    #    ---------------------
    -    #         (a -- b d)
    +    # First rule.
    +    #
    +    #       (a -- b) (-- d)
    +    #    ---------------------
    +    #         (a -- b d)
     
    -    if not g_in:
    +    if not g_in:
     
    -        fg_in, fg_out = f_in, f_out + g_out
    +        fg_in, fg_out = f_in, f_out + g_out
     
    -    # Second rule.
    -    #
    -    #       (a --) (c -- d)
    -    #    ---------------------
    -    #         (c a -- d)
    +    # Second rule.
    +    #
    +    #       (a --) (c -- d)
    +    #    ---------------------
    +    #         (c a -- d)
     
    -    elif not f_out:
    +    elif not f_out:
     
    -        fg_in, fg_out = g_in + f_in, g_out
    +        fg_in, fg_out = g_in + f_in, g_out
     
    -    else: # Unify, update, recur.
    +    else: # Unify, update, recur.
     
    -        fo, gi = f_out[-1], g_in[-1]
    +        fo, gi = f_out[-1], g_in[-1]
     
    -        s = unify(gi, fo)
    +        s = unify(gi, fo)
     
    -        if s == False:  # s can also be the empty dict, which is ok.
    -            raise TypeError('Cannot unify %r and %r.' % (fo, gi))
    +        if s == False:  # s can also be the empty dict, which is ok.
    +            raise TypeError('Cannot unify %r and %r.' % (fo, gi))
     
    -        f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out)
    +        f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out)
     
    -        if s: f_g = update(s, f_g)
    +        if s: f_g = update(s, f_g)
     
    -        fg_in, fg_out = compose(*f_g)
    +        fg_in, fg_out = compose(*f_g)
     
    -    return fg_in, fg_out
    +    return fg_in, fg_out
     

    unify()¶

    -
    def unify(u, v, s=None):
    -    if s is None:
    -        s = {}
    +
    def unify(u, v, s=None):
    +    if s is None:
    +        s = {}
     
    -    if isinstance(u, int):
    -        s[u] = v
    -    elif isinstance(v, int):
    -        s[v] = u
    -    else:
    -        s = False
    +    if isinstance(u, int):
    +        s[u] = v
    +    elif isinstance(v, int):
    +        s[v] = u
    +    else:
    +        s = False
     
    -    return s
    +    return s
     

    update()¶

    -
    def update(s, term):
    -    if not isinstance(term, tuple):
    -        return s.get(term, term)
    -    return tuple(update(s, inner) for inner in term)
    +
    def update(s, term):
    +    if not isinstance(term, tuple):
    +        return s.get(term, term)
    +    return tuple(update(s, inner) for inner in term)
     

    relabel()¶

    -
    def relabel(left, right):
    -    return left, _1000(right)
    +
    def relabel(left, right):
    +    return left, _1000(right)
     
    -def _1000(right):
    -    if not isinstance(right, tuple):
    -        return 1000 + right
    -    return tuple(_1000(n) for n in right)
    +def _1000(right):
    +    if not isinstance(right, tuple):
    +        return 1000 + right
    +    return tuple(_1000(n) for n in right)
     
    -relabel(pop, swap)
    +relabel(pop, swap)
     
    (((1,), ()), ((1001, 1002), (1002, 1001)))
    @@ -446,21 +446,21 @@ relabel(pop, swap)
     

    delabel()¶

    -
    def delabel(f):
    -    s = {u: i for i, u in enumerate(sorted(_unique(f)))}
    -    return update(s, f)
    +
    def delabel(f):
    +    s = {u: i for i, u in enumerate(sorted(_unique(f)))}
    +    return update(s, f)
     
    -def _unique(f, seen=None):
    -    if seen is None:
    -        seen = set()
    -    if not isinstance(f, tuple):
    -        seen.add(f)
    -    else:
    -        for inner in f:
    -            _unique(inner, seen)
    -    return seen
    +def _unique(f, seen=None):
    +    if seen is None:
    +        seen = set()
    +    if not isinstance(f, tuple):
    +        seen.add(f)
    +    else:
    +        for inner in f:
    +            _unique(inner, seen)
    +    return seen
     
    -delabel(relabel(pop, swap))
    +delabel(relabel(pop, swap))
     
    (((0,), ()), ((1, 2), (2, 1)))
    @@ -472,39 +472,39 @@ delabel(relabel(pop, swap))
     

    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.)

    -
    def C(f, g):
    -    f, g = relabel(f, g)
    -    fg = compose(f, g)
    -    return delabel(fg)
    +
    def C(f, g):
    +    f, g = relabel(f, g)
    +    fg = compose(f, g)
    +    return delabel(fg)
     

    Let’s try it out.

    -
    C(pop, swap)
    +
    C(pop, swap)
     
    ((1, 2, 0), (2, 1))
     
    -
    C(C(pop, swap), roll_dn)
    +
    C(C(pop, swap), roll_dn)
     
    ((3, 1, 2, 0), (2, 1, 3))
     
    -
    C(swap, roll_dn)
    +
    C(swap, roll_dn)
     
    ((2, 0, 1), (1, 0, 2))
     
    -
    C(pop, C(swap, roll_dn))
    +
    C(pop, C(swap, roll_dn))
     
    ((3, 1, 2, 0), (2, 1, 3))
     
    -
    poswrd = reduce(C, (pop, swap, roll_dn))
    -poswrd
    +
    poswrd = reduce(C, (pop, swap, roll_dn))
    +poswrd
     
    ((3, 1, 2, 0), (2, 1, 3))
    @@ -516,12 +516,12 @@ poswrd
     

    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.

    -
    rest = ((1, 2),), (2,)
    +
    rest = ((1, 2),), (2,)
     
    -cons = (1, 2), ((1, 2),)
    +cons = (1, 2), ((1, 2),)
     
    -
    C(poswrd, rest)
    +
    C(poswrd, rest)
     
    (((3, 4), 1, 2, 0), (2, 1, 4))
    @@ -542,9 +542,9 @@ cons = (1, 2), ((1, 2),)
     }
     
    -
    F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
    +
    F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
     
    -F
    +F
     
    (((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),))
    @@ -560,13 +560,13 @@ F
     

    Dealing with cons and uncons¶

    However, if we try to compose e.g. cons and uncons it won’t work:

    -
    uncons = ((1, 2),), (1, 2)
    +
    uncons = ((1, 2),), (1, 2)
     
    -
    try:
    -    C(cons, uncons)
    -except Exception, e:
    -    print e
    +
    try:
    +    C(cons, uncons)
    +except Exception, e:
    +    print e
     
    Cannot unify (1, 2) and (1001, 1002).
    @@ -577,36 +577,36 @@ except Exception, e:
     

    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:

    -
    def unify(u, v, s=None):
    -    if s is None:
    -        s = {}
    -    elif s:
    -        u = update(s, u)
    -        v = update(s, v)
    +
    def unify(u, v, s=None):
    +    if s is None:
    +        s = {}
    +    elif s:
    +        u = update(s, u)
    +        v = update(s, v)
     
    -    if isinstance(u, int):
    -        s[u] = v
    +    if isinstance(u, int):
    +        s[u] = v
     
    -    elif isinstance(v, int):
    -        s[v] = u
    +    elif isinstance(v, int):
    +        s[v] = u
     
    -    elif isinstance(u, tuple) and isinstance(v, tuple):
    +    elif isinstance(u, tuple) and isinstance(v, tuple):
     
    -        if len(u) != 2 or len(v) != 2:
    -            # Not a type error, caller passed in a bad value.
    -            raise ValueError(repr((u, v)))  # FIXME this message sucks.
    +        if len(u) != 2 or len(v) != 2:
    +            # Not a type error, caller passed in a bad value.
    +            raise ValueError(repr((u, v)))  # FIXME this message sucks.
     
    -        (a, b), (c, d) = u, v
    -        s = unify(a, c, s)
    -        if s != False:
    -            s = unify(b, d, s)
    -    else:
    -        s = False
    +        (a, b), (c, d) = u, v
    +        s = unify(a, c, s)
    +        if s != False:
    +            s = unify(b, d, s)
    +    else:
    +        s = False
     
    -    return s
    +    return s
     
    -
    C(cons, uncons)
    +
    C(cons, uncons)
     
    ((0, 1), (0, 1))
    @@ -618,13 +618,13 @@ deal with this recursively:

    Part III: Compiling Yin Functions¶

    Now consider the Python function we would like to derive:

    -
    def F_python(stack):
    -    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
    -    return (d, (c, S0)), stack
    +
    def F_python(stack):
    +    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
    +    return (d, (c, S0)), stack
     

    And compare it to the input stack effect comment tuple we just computed:

    -
    F[0]
    +
    F[0]
     
    ((3, (4, 5)), 1, 2, 0)
    @@ -646,7 +646,7 @@ stack effect comment tuple, just in the reverse order:

    Eh?

    And the return tuple

    -
    F[1]
    +
    F[1]
     
    ((2, (1, 5)),)
    @@ -666,21 +666,21 @@ effect.)

    Python Identifiers¶

    We want to substitute Python identifiers for the integers. I’m going to repurpose joy.parser.Symbol class for this:

    -
    from collections import defaultdict
    -from joy.parser import Symbol
    +
    from collections import defaultdict
    +from joy.parser import Symbol
     
     
    -def _names_for():
    -    I = iter(xrange(1000))
    -    return lambda: Symbol('a%i' % next(I))
    +def _names_for():
    +    I = iter(xrange(1000))
    +    return lambda: Symbol('a%i' % next(I))
     
     
    -def identifiers(term, s=None):
    -    if s is None:
    -        s = defaultdict(_names_for())
    -    if isinstance(term, int):
    -        return s[term]
    -    return tuple(identifiers(inner, s) for inner in term)
    +def identifiers(term, s=None):
    +    if s is None:
    +        s = defaultdict(_names_for())
    +    if isinstance(term, int):
    +        return s[term]
    +    return tuple(identifiers(inner, s) for inner in term)
     
    @@ -690,36 +690,36 @@ def identifiers(term, s=None): 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.

    -
    def doc_from_stack_effect(inputs, outputs):
    -    return '(%s--%s)' % (
    -        ' '.join(map(_to_str, inputs + ('',))),
    -        ' '.join(map(_to_str, ('',) + outputs))
    -    )
    -
    -
    -def _to_str(term):
    -    if not isinstance(term, tuple):
    -        try:
    -            t = term.prefix == 's'
    -        except AttributeError:
    -            return str(term)
    -        return '[.%i.]' % term.number if t else str(term)
    -
    -    a = []
    -    while term and isinstance(term, tuple):
    -        item, term = term
    -        a.append(_to_str(item))
    -
    -    try:
    -        n = term.number
    -    except AttributeError:
    -        n = term
    -    else:
    -        if term.prefix != 's':
    -            raise ValueError('Stack label: %s' % (term,))
    -
    -    a.append('.%s.' % (n,))
    -    return '[%s]' % ' '.join(a)
    +
    def doc_from_stack_effect(inputs, outputs):
    +    return '(%s--%s)' % (
    +        ' '.join(map(_to_str, inputs + ('',))),
    +        ' '.join(map(_to_str, ('',) + outputs))
    +    )
    +
    +
    +def _to_str(term):
    +    if not isinstance(term, tuple):
    +        try:
    +            t = term.prefix == 's'
    +        except AttributeError:
    +            return str(term)
    +        return '[.%i.]' % term.number if t else str(term)
    +
    +    a = []
    +    while term and isinstance(term, tuple):
    +        item, term = term
    +        a.append(_to_str(item))
    +
    +    try:
    +        n = term.number
    +    except AttributeError:
    +        n = term
    +    else:
    +        if term.prefix != 's':
    +            raise ValueError('Stack label: %s' % (term,))
    +
    +    a.append('.%s.' % (n,))
    +    return '[%s]' % ' '.join(a)
     
    @@ -728,25 +728,25 @@ def _to_str(term):

    Now we can write a compiler function to emit Python source code. (The underscore suffix distiguishes it from the built-in compile() function.)

    -
    def compile_(name, f, doc=None):
    -    if doc is None:
    -        doc = doc_from_stack_effect(*f)
    -    inputs, outputs = identifiers(f)
    -    i = o = Symbol('stack')
    -    for term in inputs:
    -        i = term, i
    -    for term in outputs:
    -        o = term, o
    -    return '''def %s(stack):
    -    """%s"""
    -    %s = stack
    -    return %s''' % (name, doc, i, o)
    +
    def compile_(name, f, doc=None):
    +    if doc is None:
    +        doc = doc_from_stack_effect(*f)
    +    inputs, outputs = identifiers(f)
    +    i = o = Symbol('stack')
    +    for term in inputs:
    +        i = term, i
    +    for term in outputs:
    +        o = term, o
    +    return '''def %s(stack):
    +    """%s"""
    +    %s = stack
    +    return %s''' % (name, doc, i, o)
     

    Here it is in action:

    -
    source = compile_('F', F)
    +
    source = compile_('F', F)
     
    -print source
    +print source
     
    def F(stack):
    @@ -756,31 +756,31 @@ print source
     

    Compare:

    -
    def F_python(stack):
    -    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
    -    return ((d, (c, S0)), stack)
    +
    def F_python(stack):
    +    (_, (d, (c, ((a, (b, S0)), stack)))) = stack
    +    return ((d, (c, S0)), stack)
     

    Next steps:

    -
    L = {}
    +
    L = {}
     
    -eval(compile(source, '__main__', 'single'), {}, L)
    +eval(compile(source, '__main__', 'single'), {}, L)
     
    -L['F']
    +L['F']
     
    <function F>
     

    Let’s try it out:

    -
    from notebook_preamble import D, J, V
    -from joy.library import SimpleFunctionWrapper
    +
    from notebook_preamble import D, J, V
    +from joy.library import SimpleFunctionWrapper
     
    -
    D['F'] = SimpleFunctionWrapper(L['F'])
    +
    D['F'] = SimpleFunctionWrapper(L['F'])
     
    -
    J('[4 5 ...] 2 3 1 F')
    +
    J('[4 5 ...] 2 3 1 F')
     
    [3 2 ...]
    @@ -800,33 +800,33 @@ this might be less helpful.

    Compiling Library Functions¶

    We can use compile_() to generate many primitives in the library from their stack effect comments:

    -
    def defs():
    +
    def defs():
     
    -    rolldown = (1, 2, 3), (2, 3, 1)
    +    rolldown = (1, 2, 3), (2, 3, 1)
     
    -    rollup = (1, 2, 3), (3, 1, 2)
    +    rollup = (1, 2, 3), (3, 1, 2)
     
    -    pop = (1,), ()
    +    pop = (1,), ()
     
    -    swap = (1, 2), (2, 1)
    +    swap = (1, 2), (2, 1)
     
    -    rest = ((1, 2),), (2,)
    +    rest = ((1, 2),), (2,)
     
    -    rrest = C(rest, rest)
    +    rrest = C(rest, rest)
     
    -    cons = (1, 2), ((1, 2),)
    +    cons = (1, 2), ((1, 2),)
     
    -    uncons = ((1, 2),), (1, 2)
    +    uncons = ((1, 2),), (1, 2)
     
    -    swons = C(swap, cons)
    +    swons = C(swap, cons)
     
    -    return locals()
    +    return locals()
     
    -
    for name, stack_effect_comment in sorted(defs().items()):
    -    print
    -    print compile_(name, stack_effect_comment)
    -    print
    +
    for name, stack_effect_comment in sorted(defs().items()):
    +    print
    +    print compile_(name, stack_effect_comment)
    +    print
     
    def cons(stack):
    @@ -966,57 +966,57 @@ and t
     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.

    -
    class AnyJoyType(object):
    +
    class AnyJoyType(object):
     
    -    prefix = 'a'
    +    prefix = 'a'
     
    -    def __init__(self, number):
    -        self.number = number
    +    def __init__(self, number):
    +        self.number = number
     
    -    def __repr__(self):
    -        return self.prefix + str(self.number)
    +    def __repr__(self):
    +        return self.prefix + str(self.number)
     
    -    def __eq__(self, other):
    -        return (
    -            isinstance(other, self.__class__)
    -            and other.prefix == self.prefix
    -            and other.number == self.number
    -        )
    +    def __eq__(self, other):
    +        return (
    +            isinstance(other, self.__class__)
    +            and other.prefix == self.prefix
    +            and other.number == self.number
    +        )
     
    -    def __ge__(self, other):
    -        return issubclass(other.__class__, self.__class__)
    +    def __ge__(self, other):
    +        return issubclass(other.__class__, self.__class__)
     
    -    def __add__(self, other):
    -        return self.__class__(self.number + other)
    -    __radd__ = __add__
    +    def __add__(self, other):
    +        return self.__class__(self.number + other)
    +    __radd__ = __add__
     
    -    def __hash__(self):
    -        return hash(repr(self))
    +    def __hash__(self):
    +        return hash(repr(self))
     
     
    -class NumberJoyType(AnyJoyType): prefix = 'n'
    -class FloatJoyType(NumberJoyType): prefix = 'f'
    -class IntJoyType(FloatJoyType): prefix = 'i'
    +class NumberJoyType(AnyJoyType): prefix = 'n'
    +class FloatJoyType(NumberJoyType): prefix = 'f'
    +class IntJoyType(FloatJoyType): prefix = 'i'
     
     
    -class StackJoyType(AnyJoyType):
    -    prefix = 's'
    +class StackJoyType(AnyJoyType):
    +    prefix = 's'
     
     
    -_R = range(10)
    -A = map(AnyJoyType, _R)
    -N = map(NumberJoyType, _R)
    -S = map(StackJoyType, _R)
    +_R = range(10)
    +A = map(AnyJoyType, _R)
    +N = map(NumberJoyType, _R)
    +S = map(StackJoyType, _R)
     

    Mess with it a little:

    -
    from itertools import permutations
    +
    from itertools import permutations
     

    “Any” types can be specialized to numbers and stacks, but not vice versa:

    -
    for a, b in permutations((A[0], N[0], S[0]), 2):
    -    print a, '>=', b, '->', a >= b
    +
    for a, b in permutations((A[0], N[0], S[0]), 2):
    +    print a, '>=', b, '->', a >= b
     
    a0 >= n0 -> True
    @@ -1030,8 +1030,8 @@ versa:

    Our crude Numerical Tower of numbers > floats > integers works as well (but we’re not going to use it yet):

    -
    for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
    -    print a, '>=', b, '->', a >= b
    +
    for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2):
    +    print a, '>=', b, '->', a >= b
     
    a0 >= n0 -> True
    @@ -1051,18 +1051,18 @@ Tower of numbers >
     

    Typing sqr¶

    -
    dup = (A[1],), (A[1], A[1])
    +
    dup = (A[1],), (A[1], A[1])
     
    -mul = (N[1], N[2]), (N[3],)
    +mul = (N[1], N[2]), (N[3],)
     
    -
    dup
    +
    dup
     
    ((a1,), (a1, a1))
     
    -
    mul
    +
    mul
     
    ((n1, n2), (n3,))
    @@ -1072,9 +1072,9 @@ mul = (N[1], N[2]), (N[3],)
     

    Modifying the Inferencer¶

    Re-labeling still works fine:

    -
    foo = relabel(dup, mul)
    +
    foo = relabel(dup, mul)
     
    -foo
    +foo
     
    (((a1,), (a1, a1)), ((n1001, n1002), (n1003,)))
    @@ -1084,28 +1084,28 @@ foo
     

    delabel() version 2¶

    The delabel() function needs an overhaul. It now has to keep track of how many labels of each domain it has “seen”.

    -
    from collections import Counter
    +
    from collections import Counter
     
     
    -def delabel(f, seen=None, c=None):
    -    if seen is None:
    -        assert c is None
    -        seen, c = {}, Counter()
    +def delabel(f, seen=None, c=None):
    +    if seen is None:
    +        assert c is None
    +        seen, c = {}, Counter()
     
    -    try:
    -        return seen[f]
    -    except KeyError:
    -        pass
    +    try:
    +        return seen[f]
    +    except KeyError:
    +        pass
     
    -    if not isinstance(f, tuple):
    -        seen[f] = f.__class__(c[f.prefix] + 1)
    -        c[f.prefix] += 1
    -        return seen[f]
    +    if not isinstance(f, tuple):
    +        seen[f] = f.__class__(c[f.prefix] + 1)
    +        c[f.prefix] += 1
    +        return seen[f]
     
    -    return tuple(delabel(inner, seen, c) for inner in f)
    +    return tuple(delabel(inner, seen, c) for inner in f)
     
    -
    delabel(foo)
    +
    delabel(foo)
     
    (((a1,), (a1, a1)), ((n1, n2), (n3,)))
    @@ -1114,112 +1114,112 @@ def delabel(f, seen=None, c=None):
     

    unify() version 3¶

    -
    def unify(u, v, s=None):
    -    if s is None:
    -        s = {}
    -    elif s:
    -        u = update(s, u)
    -        v = update(s, v)
    -
    -    if u == v:
    -        return s
    -
    -    if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
    -        if u >= v:
    -            s[u] = v
    -            return s
    -        if v >= u:
    -            s[v] = u
    -            return s
    -        raise TypeError('Cannot unify %r and %r.' % (u, v))
    -
    -    if isinstance(u, tuple) and isinstance(v, tuple):
    -        if len(u) != len(v) != 2:
    -            raise TypeError(repr((u, v)))
    -        for uu, vv in zip(u, v):
    -            s = unify(uu, vv, s)
    -            if s == False: # (instead of a substitution dict.)
    -                break
    -        return s
    -
    -    if isinstance(v, tuple):
    -        if not stacky(u):
    -            raise TypeError('Cannot unify %r and %r.' % (u, v))
    -        s[u] = v
    -        return s
    -
    -    if isinstance(u, tuple):
    -        if not stacky(v):
    -            raise TypeError('Cannot unify %r and %r.' % (v, u))
    -        s[v] = u
    -        return s
    -
    -    return False
    -
    -
    -def stacky(thing):
    -    return thing.__class__ in {AnyJoyType, StackJoyType}
    +
    def unify(u, v, s=None):
    +    if s is None:
    +        s = {}
    +    elif s:
    +        u = update(s, u)
    +        v = update(s, v)
    +
    +    if u == v:
    +        return s
    +
    +    if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
    +        if u >= v:
    +            s[u] = v
    +            return s
    +        if v >= u:
    +            s[v] = u
    +            return s
    +        raise TypeError('Cannot unify %r and %r.' % (u, v))
    +
    +    if isinstance(u, tuple) and isinstance(v, tuple):
    +        if len(u) != len(v) != 2:
    +            raise TypeError(repr((u, v)))
    +        for uu, vv in zip(u, v):
    +            s = unify(uu, vv, s)
    +            if s == False: # (instead of a substitution dict.)
    +                break
    +        return s
    +
    +    if isinstance(v, tuple):
    +        if not stacky(u):
    +            raise TypeError('Cannot unify %r and %r.' % (u, v))
    +        s[u] = v
    +        return s
    +
    +    if isinstance(u, tuple):
    +        if not stacky(v):
    +            raise TypeError('Cannot unify %r and %r.' % (v, u))
    +        s[v] = u
    +        return s
    +
    +    return False
    +
    +
    +def stacky(thing):
    +    return thing.__class__ in {AnyJoyType, StackJoyType}
     

    Rewrite the stack effect comments:

    -
    def defs():
    +
    def defs():
     
    -    rolldown = (A[1], A[2], A[3]), (A[2], A[3], A[1])
    +    rolldown = (A[1], A[2], A[3]), (A[2], A[3], A[1])
     
    -    rollup = (A[1], A[2], A[3]), (A[3], A[1], A[2])
    +    rollup = (A[1], A[2], A[3]), (A[3], A[1], A[2])
     
    -    pop = (A[1],), ()
    +    pop = (A[1],), ()
     
    -    popop = (A[2], A[1],), ()
    +    popop = (A[2], A[1],), ()
     
    -    popd = (A[2], A[1],), (A[1],)
    +    popd = (A[2], A[1],), (A[1],)
     
    -    popdd = (A[3], A[2], A[1],), (A[2], A[1],)
    +    popdd = (A[3], A[2], A[1],), (A[2], A[1],)
     
    -    swap = (A[1], A[2]), (A[2], A[1])
    +    swap = (A[1], A[2]), (A[2], A[1])
     
    -    rest = ((A[1], S[1]),), (S[1],)
    +    rest = ((A[1], S[1]),), (S[1],)
     
    -    rrest = C(rest, rest)
    +    rrest = C(rest, rest)
     
    -    cons = (A[1], S[1]), ((A[1], S[1]),)
    +    cons = (A[1], S[1]), ((A[1], S[1]),)
     
    -    ccons = C(cons, cons)
    +    ccons = C(cons, cons)
     
    -    uncons = ((A[1], S[1]),), (A[1], S[1])
    +    uncons = ((A[1], S[1]),), (A[1], S[1])
     
    -    swons = C(swap, cons)
    +    swons = C(swap, cons)
     
    -    dup = (A[1],), (A[1], A[1])
    +    dup = (A[1],), (A[1], A[1])
     
    -    dupd = (A[2], A[1]), (A[2], A[2], A[1])
    +    dupd = (A[2], A[1]), (A[2], A[2], A[1])
     
    -    mul = (N[1], N[2]), (N[3],)
    +    mul = (N[1], N[2]), (N[3],)
     
    -    sqrt = C(dup, mul)
    +    sqrt = C(dup, mul)
     
    -    first = ((A[1], S[1]),), (A[1],)
    +    first = ((A[1], S[1]),), (A[1],)
     
    -    second = C(rest, first)
    +    second = C(rest, first)
     
    -    third = C(rest, second)
    +    third = C(rest, second)
     
    -    tuck = (A[2], A[1]), (A[1], A[2], A[1])
    +    tuck = (A[2], A[1]), (A[1], A[2], A[1])
     
    -    over = (A[2], A[1]), (A[2], A[1], A[2])
    +    over = (A[2], A[1]), (A[2], A[1], A[2])
     
    -    succ = pred = (N[1],), (N[2],)
    +    succ = pred = (N[1],), (N[2],)
     
    -    divmod_ = pm = (N[2], N[1]), (N[4], N[3])
    +    divmod_ = pm = (N[2], N[1]), (N[4], N[3])
     
    -    return locals()
    +    return locals()
     
    -
    DEFS = defs()
    +
    DEFS = defs()
     
    -
    for name, stack_effect_comment in sorted(DEFS.items()):
    -    print name, '=', doc_from_stack_effect(*stack_effect_comment)
    +
    for name, stack_effect_comment in sorted(DEFS.items()):
    +    print name, '=', doc_from_stack_effect(*stack_effect_comment)
     
    ccons = (a1 a2 [.1.] -- [a1 a2 .1.])
    @@ -1250,27 +1250,27 @@ def stacky(thing):
     uncons = ([a1 .1.] -- a1 [.1.])
     
    -
    globals().update(DEFS)
    +
    globals().update(DEFS)
     

    Compose dup and mul¶

    -
    C(dup, mul)
    +
    C(dup, mul)
     
    ((n1,), (n2,))
     

    Revisit the F function, works fine.

    -
    F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
    -F
    +
    F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons))
    +F
     
    (((a1, (a2, s1)), a3, a4, a5), ((a4, (a3, s1)),))
     
    -
    print doc_from_stack_effect(*F)
    +
    print doc_from_stack_effect(*F)
     
    ([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.])
    @@ -1278,26 +1278,26 @@ F
     

    Some otherwise inefficient functions are no longer to be feared. We can also get the effect of combinators in some limited cases.

    -
    def neato(*funcs):
    -    print doc_from_stack_effect(*reduce(C, funcs))
    +
    def neato(*funcs):
    +    print doc_from_stack_effect(*reduce(C, funcs))
     
    -
    # e.g. [swap] dip
    -neato(rollup, swap, rolldown)
    +
    # e.g. [swap] dip
    +neato(rollup, swap, rolldown)
     
    (a1 a2 a3 -- a2 a1 a3)
     
    -
    # e.g. [popop] dipd
    -neato(popdd, rolldown, pop)
    +
    # e.g. [popop] dipd
    +neato(popdd, rolldown, pop)
     
    (a1 a2 a3 a4 -- a3 a4)
     
    -
    # Reverse the order of the top three items.
    -neato(rollup, swap)
    +
    # Reverse the order of the top three items.
    +neato(rollup, swap)
     
    (a1 a2 a3 -- a3 a2 a1)
    @@ -1308,22 +1308,22 @@ neato(rollup, swap)
     

    compile_() version 2¶

    Because the type labels represent themselves as valid Python identifiers the compile_() function doesn’t need to generate them anymore:

    -
    def compile_(name, f, doc=None):
    -    inputs, outputs = f
    -    if doc is None:
    -        doc = doc_from_stack_effect(inputs, outputs)
    -    i = o = Symbol('stack')
    -    for term in inputs:
    -        i = term, i
    -    for term in outputs:
    -        o = term, o
    -    return '''def %s(stack):
    -    """%s"""
    -    %s = stack
    -    return %s''' % (name, doc, i, o)
    +
    def compile_(name, f, doc=None):
    +    inputs, outputs = f
    +    if doc is None:
    +        doc = doc_from_stack_effect(inputs, outputs)
    +    i = o = Symbol('stack')
    +    for term in inputs:
    +        i = term, i
    +    for term in outputs:
    +        o = term, o
    +    return '''def %s(stack):
    +    """%s"""
    +    %s = stack
    +    return %s''' % (name, doc, i, o)
     
    -
    print compile_('F', F)
    +
    print compile_('F', F)
     
    def F(stack):
    @@ -1334,7 +1334,7 @@ the compile_()
     

    But it cannot magically create new functions that involve e.g. math and such. Note that this is not a sqr function implementation:

    -
    print compile_('sqr', C(dup, mul))
    +
    print compile_('sqr', C(dup, mul))
     
    def sqr(stack):
    @@ -1356,16 +1356,16 @@ functions (at least) are already wrappers it should be straightforward.)

    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:

    -
    from itertools import imap
    +
    from itertools import imap
     
     
    -def compilable(f):
    -    return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f)
    +def compilable(f):
    +    return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f)
     
    -
    for name, stack_effect_comment in sorted(defs().items()):
    -    if compilable(stack_effect_comment):
    -        print name, '=', doc_from_stack_effect(*stack_effect_comment)
    +
    for name, stack_effect_comment in sorted(defs().items()):
    +    if compilable(stack_effect_comment):
    +        print name, '=', doc_from_stack_effect(*stack_effect_comment)
     
    ccons = (a1 a2 [.1.] -- [a1 a2 .1.])
    @@ -1465,36 +1465,36 @@ first two rules’ 
     the “truthiness” of StackJoyType to false to let e.g.
     joy.utils.stack.concat work with our stack effect comment cons-list
     tuples.)

    -
    def compose(f, g):
    -    (f_in, f_out), (g_in, g_out) = f, g
    -    s = unify(g_in, f_out)
    -    if s == False:  # s can also be the empty dict, which is ok.
    -        raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
    -    return update(s, (f_in, g_out))
    +
    def compose(f, g):
    +    (f_in, f_out), (g_in, g_out) = f, g
    +    s = unify(g_in, f_out)
    +    if s == False:  # s can also be the empty dict, which is ok.
    +        raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
    +    return update(s, (f_in, g_out))
     

    I don’t want to rewrite all the defs myself, so I’ll write a little conversion function instead. This is programmer’s laziness.

    -
    def sequence_to_stack(seq, stack=StackJoyType(23)):
    -    for item in seq: stack = item, stack
    -    return stack
    +
    def sequence_to_stack(seq, stack=StackJoyType(23)):
    +    for item in seq: stack = item, stack
    +    return stack
     
    -NEW_DEFS = {
    -    name: (sequence_to_stack(i), sequence_to_stack(o))
    -    for name, (i, o) in DEFS.iteritems()
    -}
    -NEW_DEFS['stack'] = S[0], (S[0], S[0])
    -NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1])
    -globals().update(NEW_DEFS)
    +NEW_DEFS = {
    +    name: (sequence_to_stack(i), sequence_to_stack(o))
    +    for name, (i, o) in DEFS.iteritems()
    +}
    +NEW_DEFS['stack'] = S[0], (S[0], S[0])
    +NEW_DEFS['swaack'] = (S[1], S[0]), (S[0], S[1])
    +globals().update(NEW_DEFS)
     
    -
    C(stack, uncons)
    +
    C(stack, uncons)
     
    ((a1, s1), (s1, (a1, (a1, s1))))
     
    -
    reduce(C, (stack, uncons, uncons))
    +
    reduce(C, (stack, uncons, uncons))
     
    ((a1, (a2, s1)), (s1, (a2, (a1, (a1, (a2, s1))))))
    @@ -1506,55 +1506,55 @@ globals().update(NEW_DEFS)
     

    doc_from_stack_effect() version 2¶

    Clunky junk, but it will suffice for now.

    -
    def doc_from_stack_effect(inputs, outputs):
    -    switch = [False]  # Do we need to display the '...' for the rest of the main stack?
    -    i, o = _f(inputs, switch), _f(outputs, switch)
    -    if switch[0]:
    -        i.append('...')
    -        o.append('...')
    -    return '(%s--%s)' % (
    -        ' '.join(reversed([''] + i)),
    -        ' '.join(reversed(o + [''])),
    -    )
    -
    -
    -def _f(term, switch):
    -    a = []
    -    while term and isinstance(term, tuple):
    -        item, term = term
    -        a.append(item)
    -    assert isinstance(term, StackJoyType), repr(term)
    -    a = [_to_str(i, term, switch) for i in a]
    -    return a
    -
    -
    -def _to_str(term, stack, switch):
    -    if not isinstance(term, tuple):
    -        if term == stack:
    -            switch[0] = True
    -            return '[...]'
    -        return (
    -            '[.%i.]' % term.number
    -            if isinstance(term, StackJoyType)
    -            else str(term)
    -        )
    -
    -    a = []
    -    while term and isinstance(term, tuple):
    -        item, term = term
    -        a.append(_to_str(item, stack, switch))
    -    assert isinstance(term, StackJoyType), repr(term)
    -    if term == stack:
    -        switch[0] = True
    -        end = '...'
    -    else:
    -        end = '.%i.' % term.number
    -    a.append(end)
    -    return '[%s]' % ' '.join(a)
    -
    -
    -
    for name, stack_effect_comment in sorted(NEW_DEFS.items()):
    -    print name, '=', doc_from_stack_effect(*stack_effect_comment)
    +
    def doc_from_stack_effect(inputs, outputs):
    +    switch = [False]  # Do we need to display the '...' for the rest of the main stack?
    +    i, o = _f(inputs, switch), _f(outputs, switch)
    +    if switch[0]:
    +        i.append('...')
    +        o.append('...')
    +    return '(%s--%s)' % (
    +        ' '.join(reversed([''] + i)),
    +        ' '.join(reversed(o + [''])),
    +    )
    +
    +
    +def _f(term, switch):
    +    a = []
    +    while term and isinstance(term, tuple):
    +        item, term = term
    +        a.append(item)
    +    assert isinstance(term, StackJoyType), repr(term)
    +    a = [_to_str(i, term, switch) for i in a]
    +    return a
    +
    +
    +def _to_str(term, stack, switch):
    +    if not isinstance(term, tuple):
    +        if term == stack:
    +            switch[0] = True
    +            return '[...]'
    +        return (
    +            '[.%i.]' % term.number
    +            if isinstance(term, StackJoyType)
    +            else str(term)
    +        )
    +
    +    a = []
    +    while term and isinstance(term, tuple):
    +        item, term = term
    +        a.append(_to_str(item, stack, switch))
    +    assert isinstance(term, StackJoyType), repr(term)
    +    if term == stack:
    +        switch[0] = True
    +        end = '...'
    +    else:
    +        end = '.%i.' % term.number
    +    a.append(end)
    +    return '[%s]' % ' '.join(a)
    +
    +
    +
    for name, stack_effect_comment in sorted(NEW_DEFS.items()):
    +    print name, '=', doc_from_stack_effect(*stack_effect_comment)
     
    ccons = (a1 a2 [.1.] -- [a1 a2 .1.])
    @@ -1587,10 +1587,10 @@ def _to_str(term, stack, switch):
     uncons = ([a1 .1.] -- a1 [.1.])
     
    -
    print ; print doc_from_stack_effect(*stack)
    -print ; print doc_from_stack_effect(*C(stack, uncons))
    -print ; print doc_from_stack_effect(*reduce(C, (stack, uncons, uncons)))
    -print ; print doc_from_stack_effect(*reduce(C, (stack, uncons, cons)))
    +
    print ; print doc_from_stack_effect(*stack)
    +print ; print doc_from_stack_effect(*C(stack, uncons))
    +print ; print doc_from_stack_effect(*reduce(C, (stack, uncons, uncons)))
    +print ; print doc_from_stack_effect(*reduce(C, (stack, uncons, cons)))
     
    (... -- ... [...])
    @@ -1602,15 +1602,15 @@ print ; print doc_from_stack_effect(*reduce(C, (stack, uncons, cons)))
     (... a1 -- ... a1 [a1 ...])
     
    -
    print doc_from_stack_effect(*C(ccons, stack))
    +
    print doc_from_stack_effect(*C(ccons, stack))
     
    (... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])
     
    -
    Q = C(ccons, stack)
    +
    Q = C(ccons, stack)
     
    -Q
    +Q
     
    ((s1, (a1, (a2, s2))), (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2)))
    @@ -1620,17 +1620,17 @@ Q
     

    compile_() version 3¶

    This makes the compile_() function pretty simple as the stack effect comments are now already in the form needed for the Python code:

    -
    def compile_(name, f, doc=None):
    -    i, o = f
    -    if doc is None:
    -        doc = doc_from_stack_effect(i, o)
    -    return '''def %s(stack):
    -    """%s"""
    -    %s = stack
    -    return %s''' % (name, doc, i, o)
    +
    def compile_(name, f, doc=None):
    +    i, o = f
    +    if doc is None:
    +        doc = doc_from_stack_effect(i, o)
    +    return '''def %s(stack):
    +    """%s"""
    +    %s = stack
    +    return %s''' % (name, doc, i, o)
     
    -
    print compile_('Q', Q)
    +
    print compile_('Q', Q)
     
    def Q(stack):
    @@ -1639,35 +1639,35 @@ comments are now already in the form needed for the Python code:

    return (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2))
    -
    unstack = (S[1], S[0]), S[1]
    -enstacken = S[0], (S[0], S[1])
    +
    unstack = (S[1], S[0]), S[1]
    +enstacken = S[0], (S[0], S[1])
     
    -
    print doc_from_stack_effect(*unstack)
    +
    print doc_from_stack_effect(*unstack)
     
    ([.1.] --)
     
    -
    print doc_from_stack_effect(*enstacken)
    +
    print doc_from_stack_effect(*enstacken)
     
    (-- [.0.])
     
    -
    print doc_from_stack_effect(*C(cons, unstack))
    +
    print doc_from_stack_effect(*C(cons, unstack))
     
    (a1 [.1.] -- a1)
     
    -
    print doc_from_stack_effect(*C(cons, enstacken))
    +
    print doc_from_stack_effect(*C(cons, enstacken))
     
    (a1 [.1.] -- [[a1 .1.] .2.])
     
    -
    C(cons, unstack)
    +
    C(cons, unstack)
     
    ((s1, (a1, s2)), (a1, s1))
    @@ -1679,23 +1679,23 @@ enstacken = S[0], (S[0], S[1])
     

    Part VI: Multiple Stack Effects¶

    …

    -
    class IntJoyType(NumberJoyType): prefix = 'i'
    +
    class IntJoyType(NumberJoyType): prefix = 'i'
     
     
    -F = map(FloatJoyType, _R)
    -I = map(IntJoyType, _R)
    +F = map(FloatJoyType, _R)
    +I = map(IntJoyType, _R)
     
    -
    muls = [
    -     ((I[2], (I[1], S[0])), (I[3], S[0])),
    -     ((F[2], (I[1], S[0])), (F[3], S[0])),
    -     ((I[2], (F[1], S[0])), (F[3], S[0])),
    -     ((F[2], (F[1], S[0])), (F[3], S[0])),
    -]
    +
    muls = [
    +     ((I[2], (I[1], S[0])), (I[3], S[0])),
    +     ((F[2], (I[1], S[0])), (F[3], S[0])),
    +     ((I[2], (F[1], S[0])), (F[3], S[0])),
    +     ((F[2], (F[1], S[0])), (F[3], S[0])),
    +]
     
    -
    for f in muls:
    -    print doc_from_stack_effect(*f)
    +
    for f in muls:
    +    print doc_from_stack_effect(*f)
     
    (i1 i2 -- i3)
    @@ -1704,42 +1704,42 @@ I = map(IntJoyType, _R)
     (f1 f2 -- f3)
     
    -
    for f in muls:
    -    try:
    -        e = C(dup, f)
    -    except TypeError:
    -        continue
    -    print doc_from_stack_effect(*dup), doc_from_stack_effect(*f), doc_from_stack_effect(*e)
    +
    for f in muls:
    +    try:
    +        e = C(dup, f)
    +    except TypeError:
    +        continue
    +    print doc_from_stack_effect(*dup), doc_from_stack_effect(*f), doc_from_stack_effect(*e)
     
    (a1 -- a1 a1) (i1 i2 -- i3) (i1 -- i2)
     (a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2)
     
    -
    from itertools import product
    +
    from itertools import product
     
     
    -def meta_compose(F, G):
    -    for f, g in product(F, G):
    -        try:
    -            yield C(f, g)
    -        except TypeError:
    -            pass
    +def meta_compose(F, G):
    +    for f, g in product(F, G):
    +        try:
    +            yield C(f, g)
    +        except TypeError:
    +            pass
     
     
    -def MC(F, G):
    -    return sorted(set(meta_compose(F, G)))
    +def MC(F, G):
    +    return sorted(set(meta_compose(F, G)))
     
    -
    for f in MC([dup], [mul]):
    -    print doc_from_stack_effect(*f)
    +
    for f in MC([dup], [mul]):
    +    print doc_from_stack_effect(*f)
     
    (n1 -- n2)
     
    -
    for f in MC([dup], muls):
    -    print doc_from_stack_effect(*f)
    +
    for f in MC([dup], muls):
    +    print doc_from_stack_effect(*f)
     
    (f1 -- f2)
    @@ -1793,148 +1793,148 @@ disappears:

    {c: a, d: e, .1.: A* b .0.}
    -
    class KleeneStar(object):
    +
    class KleeneStar(object):
     
    -    kind = AnyJoyType
    +    kind = AnyJoyType
     
    -    def __init__(self, number):
    -        self.number = number
    -        self.count = 0
    -        self.prefix = repr(self)
    +    def __init__(self, number):
    +        self.number = number
    +        self.count = 0
    +        self.prefix = repr(self)
     
    -    def __repr__(self):
    -        return '%s%i*' % (self.kind.prefix, self.number)
    +    def __repr__(self):
    +        return '%s%i*' % (self.kind.prefix, self.number)
     
    -    def another(self):
    -        self.count += 1
    -        return self.kind(10000 * self.number + self.count)
    +    def another(self):
    +        self.count += 1
    +        return self.kind(10000 * self.number + self.count)
     
    -    def __eq__(self, other):
    -        return (
    -            isinstance(other, self.__class__)
    -            and other.number == self.number
    -        )
    +    def __eq__(self, other):
    +        return (
    +            isinstance(other, self.__class__)
    +            and other.number == self.number
    +        )
     
    -    def __ge__(self, other):
    -        return self.kind >= other.kind
    +    def __ge__(self, other):
    +        return self.kind >= other.kind
     
    -    def __add__(self, other):
    -        return self.__class__(self.number + other)
    -    __radd__ = __add__
    +    def __add__(self, other):
    +        return self.__class__(self.number + other)
    +    __radd__ = __add__
     
    -    def __hash__(self):
    -        return hash(repr(self))
    +    def __hash__(self):
    +        return hash(repr(self))
     
    -class AnyStarJoyType(KleeneStar): kind = AnyJoyType
    -class NumberStarJoyType(KleeneStar): kind = NumberJoyType
    -#class FloatStarJoyType(KleeneStar): kind = FloatJoyType
    -#class IntStarJoyType(KleeneStar): kind = IntJoyType
    -class StackStarJoyType(KleeneStar): kind = StackJoyType
    +class AnyStarJoyType(KleeneStar): kind = AnyJoyType
    +class NumberStarJoyType(KleeneStar): kind = NumberJoyType
    +#class FloatStarJoyType(KleeneStar): kind = FloatJoyType
    +#class IntStarJoyType(KleeneStar): kind = IntJoyType
    +class StackStarJoyType(KleeneStar): kind = StackJoyType
     
     
    -As = map(AnyStarJoyType, _R)
    -Ns = map(NumberStarJoyType, _R)
    -Ss = map(StackStarJoyType, _R)
    +As = map(AnyStarJoyType, _R)
    +Ns = map(NumberStarJoyType, _R)
    +Ss = map(StackStarJoyType, _R)
     

    unify() version 4¶

    Can now return multiple results…

    -
    def unify(u, v, s=None):
    -    if s is None:
    -        s = {}
    -    elif s:
    -        u = update(s, u)
    -        v = update(s, v)
    -
    -    if u == v:
    -        return s,
    -
    -    if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
    -        if u >= v:
    -            s[u] = v
    -            return s,
    -        if v >= u:
    -            s[v] = u
    -            return s,
    -        raise TypeError('Cannot unify %r and %r.' % (u, v))
    -
    -    if isinstance(u, tuple) and isinstance(v, tuple):
    -        if len(u) != len(v) != 2:
    -            raise TypeError(repr((u, v)))
    -
    -        a, b = v
    -        if isinstance(a, KleeneStar):
    -            # Two universes, in one the Kleene star disappears and unification
    -            # continues without it...
    -            s0 = unify(u, b)
    -
    -            # In the other it spawns a new variable.
    -            s1 = unify(u, (a.another(), v))
    -
    -            t = s0 + s1
    -            for sn in t:
    -                sn.update(s)
    -            return t
    -
    -        a, b = u
    -        if isinstance(a, KleeneStar):
    -            s0 = unify(v, b)
    -            s1 = unify(v, (a.another(), u))
    -            t = s0 + s1
    -            for sn in t:
    -                sn.update(s)
    -            return t
    -
    -        ses = unify(u[0], v[0], s)
    -        results = ()
    -        for sn in ses:
    -            results += unify(u[1], v[1], sn)
    -        return results
    -
    -    if isinstance(v, tuple):
    -        if not stacky(u):
    -            raise TypeError('Cannot unify %r and %r.' % (u, v))
    -        s[u] = v
    -        return s,
    -
    -    if isinstance(u, tuple):
    -        if not stacky(v):
    -            raise TypeError('Cannot unify %r and %r.' % (v, u))
    -        s[v] = u
    -        return s,
    -
    -    return ()
    -
    -
    -def stacky(thing):
    -    return thing.__class__ in {AnyJoyType, StackJoyType}
    -
    -
    -
    a = (As[1], S[1])
    -a
    +
    def unify(u, v, s=None):
    +    if s is None:
    +        s = {}
    +    elif s:
    +        u = update(s, u)
    +        v = update(s, v)
    +
    +    if u == v:
    +        return s,
    +
    +    if isinstance(u, AnyJoyType) and isinstance(v, AnyJoyType):
    +        if u >= v:
    +            s[u] = v
    +            return s,
    +        if v >= u:
    +            s[v] = u
    +            return s,
    +        raise TypeError('Cannot unify %r and %r.' % (u, v))
    +
    +    if isinstance(u, tuple) and isinstance(v, tuple):
    +        if len(u) != len(v) != 2:
    +            raise TypeError(repr((u, v)))
    +
    +        a, b = v
    +        if isinstance(a, KleeneStar):
    +            # Two universes, in one the Kleene star disappears and unification
    +            # continues without it...
    +            s0 = unify(u, b)
    +
    +            # In the other it spawns a new variable.
    +            s1 = unify(u, (a.another(), v))
    +
    +            t = s0 + s1
    +            for sn in t:
    +                sn.update(s)
    +            return t
    +
    +        a, b = u
    +        if isinstance(a, KleeneStar):
    +            s0 = unify(v, b)
    +            s1 = unify(v, (a.another(), u))
    +            t = s0 + s1
    +            for sn in t:
    +                sn.update(s)
    +            return t
    +
    +        ses = unify(u[0], v[0], s)
    +        results = ()
    +        for sn in ses:
    +            results += unify(u[1], v[1], sn)
    +        return results
    +
    +    if isinstance(v, tuple):
    +        if not stacky(u):
    +            raise TypeError('Cannot unify %r and %r.' % (u, v))
    +        s[u] = v
    +        return s,
    +
    +    if isinstance(u, tuple):
    +        if not stacky(v):
    +            raise TypeError('Cannot unify %r and %r.' % (v, u))
    +        s[v] = u
    +        return s,
    +
    +    return ()
    +
    +
    +def stacky(thing):
    +    return thing.__class__ in {AnyJoyType, StackJoyType}
    +
    +
    +
    a = (As[1], S[1])
    +a
     
    (a1*, s1)
     
    -
    b = (A[1], S[2])
    -b
    +
    b = (A[1], S[2])
    +b
     
    (a1, s2)
     
    -
    for result in unify(b, a):
    -    print result, '->', update(result, a), update(result, b)
    +
    for result in unify(b, a):
    +    print result, '->', update(result, a), update(result, b)
     
    {s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2)
     {a1: a10001, s2: (a1*, s1)} -> (a1*, s1) (a10001, (a1*, s1))
     
    -
    for result in unify(a, b):
    -    print result, '->', update(result, a), update(result, b)
    +
    for result in unify(a, b):
    +    print result, '->', update(result, a), update(result, b)
     
    {s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2)
    @@ -1948,24 +1948,24 @@ b
     (a1*, s1)       [a1*]       (a2, (a1*, s1)) [a2 a1*]
     
    -
    sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0])
    +
    sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0])
     
    -print doc_from_stack_effect(*sum_)
    +print doc_from_stack_effect(*sum_)
     
    ([n1* .1.] -- n0)
     
    -
    f = (N[1], (N[2], (N[3], S[1]))), S[0]
    +
    f = (N[1], (N[2], (N[3], S[1]))), S[0]
     
    -print doc_from_stack_effect(S[0], f)
    +print doc_from_stack_effect(S[0], f)
     
    (-- [n1 n2 n3 .1.])
     
    -
    for result in unify(sum_[0], f):
    -    print result, '->', update(result, sum_[1])
    +
    for result in unify(sum_[0], f):
    +    print result, '->', update(result, sum_[1])
     
    {s1: (n1, (n2, (n3, s1)))} -> (n0, s0)
    @@ -1978,88 +1978,88 @@ print doc_from_stack_effect(S[0], f)
     

    compose() version 3¶

    This function has to be modified to yield multiple results.

    -
    def compose(f, g):
    -    (f_in, f_out), (g_in, g_out) = f, g
    -    s = unify(g_in, f_out)
    -    if not s:
    -        raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
    -    for result in s:
    -        yield update(result, (f_in, g_out))
    +
    def compose(f, g):
    +    (f_in, f_out), (g_in, g_out) = f, g
    +    s = unify(g_in, f_out)
    +    if not s:
    +        raise TypeError('Cannot unify %r and %r.' % (f_out, g_in))
    +    for result in s:
    +        yield update(result, (f_in, g_out))
     
    -
    def meta_compose(F, G):
    -    for f, g in product(F, G):
    -        try:
    -            for result in C(f, g):
    -                yield result
    -        except TypeError:
    -            pass
    +
    def meta_compose(F, G):
    +    for f, g in product(F, G):
    +        try:
    +            for result in C(f, g):
    +                yield result
    +        except TypeError:
    +            pass
     
     
    -def C(f, g):
    -    f, g = relabel(f, g)
    -    for fg in compose(f, g):
    -        yield delabel(fg)
    +def C(f, g):
    +    f, g = relabel(f, g)
    +    for fg in compose(f, g):
    +        yield delabel(fg)
     
    -
    for f in MC([dup], muls):
    -    print doc_from_stack_effect(*f)
    +
    for f in MC([dup], muls):
    +    print doc_from_stack_effect(*f)
     
    (f1 -- f2)
     (i1 -- i2)
     
    -
    for f in MC([dup], [sum_]):
    -    print doc_from_stack_effect(*f)
    +
    for f in MC([dup], [sum_]):
    +    print doc_from_stack_effect(*f)
     
    ([n1* .1.] -- [n1* .1.] n1)
     
    -
    for f in MC([cons], [sum_]):
    -    print doc_from_stack_effect(*f)
    +
    for f in MC([cons], [sum_]):
    +    print doc_from_stack_effect(*f)
     
    (a1 [.1.] -- n1)
     (n1 [n1* .1.] -- n2)
     
    -
    sum_ = (((N[1], (Ns[1], S[1])), S[0]), (N[0], S[0]))
    -print doc_from_stack_effect(*cons),
    -print doc_from_stack_effect(*sum_),
    +
    sum_ = (((N[1], (Ns[1], S[1])), S[0]), (N[0], S[0]))
    +print doc_from_stack_effect(*cons),
    +print doc_from_stack_effect(*sum_),
     
    -for f in MC([cons], [sum_]):
    -    print doc_from_stack_effect(*f)
    +for f in MC([cons], [sum_]):
    +    print doc_from_stack_effect(*f)
     
    (a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n1 [n1* .1.] -- n2)
     
    -
    a = (A[4], (As[1], (A[3], S[1])))
    -a
    +
    a = (A[4], (As[1], (A[3], S[1])))
    +a
     
    (a4, (a1*, (a3, s1)))
     
    -
    b = (A[1], (A[2], S[2]))
    -b
    +
    b = (A[1], (A[2], S[2]))
    +b
     
    (a1, (a2, s2))
     
    -
    for result in unify(b, a):
    -    print result
    +
    for result in unify(b, a):
    +    print result
     
    {a1: a4, s2: s1, a2: a3}
     {a1: a4, s2: (a1*, (a3, s1)), a2: a10003}
     
    -
    for result in unify(a, b):
    -    print result
    +
    for result in unify(a, b):
    +    print result
     
    {s2: s1, a2: a3, a4: a1}
    @@ -2111,19 +2111,19 @@ stack effect we have to “split universes” again and return both.

    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.

    -
    class FunctionJoyType(AnyJoyType):
    +
    class FunctionJoyType(AnyJoyType):
     
    -    def __init__(self, name, sec, number):
    -        self.name = name
    -        self.stack_effects = sec
    -        self.number = number
    +    def __init__(self, name, sec, number):
    +        self.name = name
    +        self.stack_effects = sec
    +        self.number = number
     
    -    def __add__(self, other):
    -        return self
    -    __radd__ = __add__
    +    def __add__(self, other):
    +        return self
    +    __radd__ = __add__
     
    -    def __repr__(self):
    -        return self.name
    +    def __repr__(self):
    +        return self.name
     
    @@ -2131,47 +2131,47 @@ name and a list of stack effects.

    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.)

    -
    class SymbolJoyType(FunctionJoyType):
    -    prefix = 'F'
    +
    class SymbolJoyType(FunctionJoyType):
    +    prefix = 'F'
     

    For combinators the list contains Python functions.

    -
    class CombinatorJoyType(FunctionJoyType):
    +
    class CombinatorJoyType(FunctionJoyType):
     
    -    prefix = 'C'
    +    prefix = 'C'
     
    -    def __init__(self, name, sec, number, expect=None):
    -        super(CombinatorJoyType, self).__init__(name, sec, number)
    -        self.expect = expect
    +    def __init__(self, name, sec, number, expect=None):
    +        super(CombinatorJoyType, self).__init__(name, sec, number)
    +        self.expect = expect
     
    -    def enter_guard(self, f):
    -        if self.expect is None:
    -            return f
    -        g = self.expect, self.expect
    -        new_f = list(compose(f, g, ()))
    -        assert len(new_f) == 1, repr(new_f)
    -        return new_f[0][1]
    +    def enter_guard(self, f):
    +        if self.expect is None:
    +            return f
    +        g = self.expect, self.expect
    +        new_f = list(compose(f, g, ()))
    +        assert len(new_f) == 1, repr(new_f)
    +        return new_f[0][1]
     

    For simple combinators that have only one effect (like dip) you only need one function and it can be the combinator itself.

    -
    import joy.library
    +
    import joy.library
     
    -dip = CombinatorJoyType('dip', [joy.library.dip], 23)
    +dip = CombinatorJoyType('dip', [joy.library.dip], 23)
     

    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.

    -
    def branch_true(stack, expression, dictionary):
    -    (then, (else_, (flag, stack))) = stack
    -    return stack, concat(then, expression), dictionary
    +
    def branch_true(stack, expression, dictionary):
    +    (then, (else_, (flag, stack))) = stack
    +    return stack, concat(then, expression), dictionary
     
    -def branch_false(stack, expression, dictionary):
    -    (then, (else_, (flag, stack))) = stack
    -    return stack, concat(else_, expression), dictionary
    +def branch_false(stack, expression, dictionary):
    +    (then, (else_, (flag, stack))) = stack
    +    return stack, concat(else_, expression), dictionary
     
    -branch = CombinatorJoyType('branch', [branch_true, branch_false], 100)
    +branch = CombinatorJoyType('branch', [branch_true, branch_false], 100)
     

    You can also provide an optional stack effect, input-side only, that @@ -2189,54 +2189,54 @@ that expression.

    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.

    -
    ID = S[0], S[0]  # Identity function.
    +
    ID = S[0], S[0]  # Identity function.
     
     
    -def infer(*expression):
    -    return sorted(set(_infer(list_to_stack(expression))))
    +def infer(*expression):
    +    return sorted(set(_infer(list_to_stack(expression))))
     
     
    -def _infer(e, F=ID):
    -    _log_it(e, F)
    -    if not e:
    -        return [F]
    +def _infer(e, F=ID):
    +    _log_it(e, F)
    +    if not e:
    +        return [F]
     
    -    n, e = e
    +    n, e = e
     
    -    if isinstance(n, SymbolJoyType):
    -        eFG = meta_compose([F], n.stack_effects, e)
    -        res = flatten(_infer(e, Fn) for e, Fn in eFG)
    +    if isinstance(n, SymbolJoyType):
    +        eFG = meta_compose([F], n.stack_effects, e)
    +        res = flatten(_infer(e, Fn) for e, Fn in eFG)
     
    -    elif isinstance(n, CombinatorJoyType):
    -        fi, fo = n.enter_guard(F)
    -        res = flatten(_interpret(f, fi, fo, e) for f in n.stack_effects)
    +    elif isinstance(n, CombinatorJoyType):
    +        fi, fo = n.enter_guard(F)
    +        res = flatten(_interpret(f, fi, fo, e) for f in n.stack_effects)
     
    -    elif isinstance(n, Symbol):
    -        assert n not in FUNCTIONS, repr(n)
    -        func = joy.library._dictionary[n]
    -        res = _interpret(func, F[0], F[1], e)
    +    elif isinstance(n, Symbol):
    +        assert n not in FUNCTIONS, repr(n)
    +        func = joy.library._dictionary[n]
    +        res = _interpret(func, F[0], F[1], e)
     
    -    else:
    -        fi, fo = F
    -        res = _infer(e, (fi, (n, fo)))
    +    else:
    +        fi, fo = F
    +        res = _infer(e, (fi, (n, fo)))
     
    -    return res
    +    return res
     
     
    -def _interpret(f, fi, fo, e):
    -    new_fo, ee, _ = f(fo, e, {})
    -    ee = update(FUNCTIONS, ee)  # Fix Symbols.
    -    new_F = fi, new_fo
    -    return _infer(ee, new_F)
    +def _interpret(f, fi, fo, e):
    +    new_fo, ee, _ = f(fo, e, {})
    +    ee = update(FUNCTIONS, ee)  # Fix Symbols.
    +    new_F = fi, new_fo
    +    return _infer(ee, new_F)
     
     
    -def _log_it(e, F):
    -    _log.info(
    -        u'%3i %s ∘ %s',
    -        len(inspect_stack()),
    -        doc_from_stack_effect(*F),
    -        expression_to_string(e),
    -        )
    +def _log_it(e, F):
    +    _log.info(
    +        u'%3i %s ∘ %s',
    +        len(inspect_stack()),
    +        doc_from_stack_effect(*F),
    +        expression_to_string(e),
    +        )
     
    @@ -2249,18 +2249,18 @@ module (FIXME link to its docs here!) should be explained… There is 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 :

    -
    1/0  # (Don't try to run this cell!  It's not going to work.  This is "read only" code heh..)
    +
    1/0  # (Don't try to run this cell!  It's not going to work.  This is "read only" code heh..)
     
    -logging.basicConfig(format='%(message)s', stream=sys.stdout, level=logging.INFO)
    +logging.basicConfig(format='%(message)s', stream=sys.stdout, level=logging.INFO)
     
    -globals().update(FUNCTIONS)
    +globals().update(FUNCTIONS)
     
    -h = infer((pred, s2), (mul, s3), (div, s4), (nullary, (bool, s5)), dipd, branch)
    +h = infer((pred, s2), (mul, s3), (div, s4), (nullary, (bool, s5)), dipd, branch)
     
    -print '-' * 40
    +print '-' * 40
     
    -for fi, fo in h:
    -    print doc_from_stack_effect(fi, fo)
    +for fi, fo in h:
    +    print doc_from_stack_effect(fi, fo)
     
    ---------------------------------------------------------------------------
    @@ -2366,14 +2366,14 @@ relational nature of the stack effect comments to “compute in reverse”
     as it were. There’s a working demo of this at the end of the types
     module. But if you’re interested in all that you should just use Prolog!

    Anyhow, type checking is a few easy steps away.

    -
    def _ge(self, other):
    -    return (issubclass(other.__class__, self.__class__)
    -            or hasattr(self, 'accept')
    -            and isinstance(other, self.accept))
    -
    -AnyJoyType.__ge__ = _ge
    -AnyJoyType.accept = tuple, int, float, long, str, unicode, bool, Symbol
    -StackJoyType.accept = tuple
    +
    def _ge(self, other):
    +    return (issubclass(other.__class__, self.__class__)
    +            or hasattr(self, 'accept')
    +            and isinstance(other, self.accept))
    +
    +AnyJoyType.__ge__ = _ge
    +AnyJoyType.accept = tuple, int, float, long, str, unicode, bool, Symbol
    +StackJoyType.accept = tuple
     
    diff --git a/docs/sphinx_docs/_build/html/notebooks/Zipper.html b/docs/sphinx_docs/_build/html/notebooks/Zipper.html index ff13a07..4653021 100644 --- a/docs/sphinx_docs/_build/html/notebooks/Zipper.html +++ b/docs/sphinx_docs/_build/html/notebooks/Zipper.html @@ -42,7 +42,7 @@ the original paper:
    from notebook_preamble import J, V, define
    +
    from notebook_preamble import J, V, define
     
    @@ -52,7 +52,7 @@ strings, Symbols (strings that are names of functions) and sequences (aka lists, aka quoted literals, aka aggregates, etc…), but we can build trees out of sequences.

    -
    J('[1 [2 [3 4 25 6] 7] 8]')
    +
    J('[1 [2 [3 4 25 6] 7] 8]')
     
    [1 [2 [3 4 25 6] 7] 8]
    @@ -75,13 +75,13 @@ datastructure used to keep track of these items is the zipper.)

    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.

    -
    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')
    +
    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')
     
    -
    V('[1 [2 [3 4 25 6] 7] 8] z-down')
    +
    V('[1 [2 [3 4 25 6] 7] 8] z-down')
     
                              . [1 [2 [3 4 25 6] 7] 8] z-down
    @@ -93,7 +93,7 @@ define('z-left == swons [uncons swap] dip swap')
     [] [[2 [3 4 25 6] 7] 8] 1 .
     
    -
    V('[] [[2 [3 4 25 6] 7] 8] 1 z-right')
    +
    V('[] [[2 [3 4 25 6] 7] 8] 1 z-right')
     
                                      . [] [[2 [3 4 25 6] 7] 8] 1 z-right
    @@ -113,43 +113,43 @@ define('z-left == swons [uncons swap] dip swap')
              [1] [8] [2 [3 4 25 6] 7] .
     
    -
    J('[1] [8] [2 [3 4 25 6] 7] z-down')
    +
    J('[1] [8] [2 [3 4 25 6] 7] z-down')
     
    [1] [8] [] [[3 4 25 6] 7] 2
     
    -
    J('[1] [8] [] [[3 4 25 6] 7] 2 z-right')
    +
    J('[1] [8] [] [[3 4 25 6] 7] 2 z-right')
     
    [1] [8] [2] [7] [3 4 25 6]
     
    -
    J('[1] [8] [2] [7] [3 4 25 6] z-down')
    +
    J('[1] [8] [2] [7] [3 4 25 6] z-down')
     
    [1] [8] [2] [7] [] [4 25 6] 3
     
    -
    J('[1] [8] [2] [7] [] [4 25 6] 3 z-right')
    +
    J('[1] [8] [2] [7] [] [4 25 6] 3 z-right')
     
    [1] [8] [2] [7] [3] [25 6] 4
     
    -
    J('[1] [8] [2] [7] [3] [25 6] 4 z-right')
    +
    J('[1] [8] [2] [7] [3] [25 6] 4 z-right')
     
    [1] [8] [2] [7] [4 3] [6] 25
     
    -
    J('[1] [8] [2] [7] [4 3] [6] 25 sqr')
    +
    J('[1] [8] [2] [7] [4 3] [6] 25 sqr')
     
    [1] [8] [2] [7] [4 3] [6] 625
     
    -
    V('[1] [8] [2] [7] [4 3] [6] 625 z-up')
    +
    V('[1] [8] [2] [7] [4 3] [6] 625 z-up')
     
                                  . [1] [8] [2] [7] [4 3] [6] 625 z-up
    @@ -168,13 +168,13 @@ define('z-left == swons [uncons swap] dip swap')
       [1] [8] [2] [7] [3 4 625 6] .
     
    -
    J('[1] [8] [2] [7] [3 4 625 6] z-up')
    +
    J('[1] [8] [2] [7] [3 4 625 6] z-up')
     
    [1] [8] [2 [3 4 625 6] 7]
     
    -
    J('[1] [8] [2 [3 4 625 6] 7] z-up')
    +
    J('[1] [8] [2 [3 4 625 6] 7] z-up')
     
    [1 [2 [3 4 625 6] 7] 8]
    @@ -185,7 +185,7 @@ define('z-left == swons [uncons swap] dip swap')
     

    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.

    -
    V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra')
    +
    V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra')
     
                                                                    . [1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra
    @@ -236,11 +236,11 @@ been embedded in a nested series of quoted programs, e.g.:

    The Z function isn’t hard to make.

    -
    define('Z == [[] cons cons] step i')
    +
    define('Z == [[] cons cons] step i')
     

    Here it is in action in a simplified scenario.

    -
    V('1 [2 3 4] Z')
    +
    V('1 [2 3 4] Z')
     
                                 . 1 [2 3 4] Z
    @@ -273,7 +273,7 @@ been embedded in a nested series of quoted programs, e.g.:

    And here it is doing the main thing.

    -
    J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z')
    +
    J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z')
     
    [1 [2 [3 4 625 6] 7] 8]
    diff --git a/docs/sphinx_docs/notebooks/Newton-Raphson.rst b/docs/sphinx_docs/notebooks/Newton-Raphson.rst
    index cb3f759..b580502 100644
    --- a/docs/sphinx_docs/notebooks/Newton-Raphson.rst
    +++ b/docs/sphinx_docs/notebooks/Newton-Raphson.rst
    @@ -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 `__
     
    -.. code:: ipython3
    +.. code:: python
     
         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:: ipython3
    +.. code:: python
     
         define('gsra 1 swap [over / + 2 /] cons [dup] swoncat make_generator')
     
    -.. code:: ipython3
    +.. code:: python
     
         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:: ipython3
    +.. code:: python
     
         J('23 gsra 6 [x popd] times first sqr')
     
    @@ -142,7 +142,7 @@ Predicate
         abs(a-b)            ε                   <=
         (abs(a-b)<=ε)
     
    -.. code:: ipython3
    +.. code:: python
     
         define('_within_P [first - abs] dip <=')
     
    @@ -156,7 +156,7 @@ Base-Case
           [b G]               first
            b
     
    -.. code:: ipython3
    +.. code:: python
     
         define('_within_B roll< popop first')
     
    @@ -184,7 +184,7 @@ Pretty straightforward:
     
         b [c G] ε within
     
    -.. code:: ipython3
    +.. code:: python
     
         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:: ipython3
    +.. code:: python
     
         define('within x 0.000000001 [_within_P] [_within_B] [_within_R] tailrec')
         define('sqrt gsra within')
     
     Try it out...
     
    -.. code:: ipython3
    +.. code:: python
     
         J('36 sqrt')
     
    @@ -216,7 +216,7 @@ Try it out...
         6.0
     
     
    -.. code:: ipython3
    +.. code:: python
     
         J('23 sqrt')
     
    @@ -228,7 +228,7 @@ Try it out...
     
     Check it.
     
    -.. code:: ipython3
    +.. code:: python
     
         4.795831523312719**2
     
    @@ -241,7 +241,7 @@ Check it.
     
     
     
    -.. code:: ipython3
    +.. code:: python
     
         from math import sqrt
         
    -- 
    2.11.0