From 3d1dc6232e532f8663e4fb4161d79d90c7a16391 Mon Sep 17 00:00:00 2001 From: Simon Forman Date: Fri, 16 Sep 2022 17:54:42 -0700 Subject: [PATCH] Remove old docs. --- docs/sphinx_docs/Makefile | 20 - .../_build/doctrees/environment.pickle | Bin 292656 -> 0 bytes .../sphinx_docs/_build/doctrees/index.doctree | Bin 23882 -> 0 bytes docs/sphinx_docs/_build/doctrees/joy.doctree | Bin 26671 -> 0 bytes docs/sphinx_docs/_build/doctrees/lib.doctree | Bin 95615 -> 0 bytes .../_build/doctrees/library.doctree | Bin 223865 -> 0 bytes .../doctrees/notebooks/Categorical.doctree | Bin 7668 -> 0 bytes ...Derivatives_of_Regular_Expressions.doctree | Bin 67567 -> 0 bytes .../doctrees/notebooks/Developing.doctree | Bin 66685 -> 0 bytes .../notebooks/Generator_Programs.doctree | Bin 48715 -> 0 bytes .../_build/doctrees/notebooks/Intro.doctree | Bin 40975 -> 0 bytes .../doctrees/notebooks/Newton-Raphson.doctree | Bin 21438 -> 0 bytes .../doctrees/notebooks/NoUpdates.doctree | Bin 8543 -> 0 bytes .../notebooks/Ordered_Binary_Trees.doctree | Bin 133172 -> 0 bytes .../doctrees/notebooks/Quadratic.doctree | Bin 20427 -> 0 bytes .../notebooks/Recursion_Combinators.doctree | Bin 70381 -> 0 bytes .../doctrees/notebooks/Replacing.doctree | Bin 30625 -> 0 bytes .../doctrees/notebooks/Square_Spiral.doctree | Bin 45962 -> 0 bytes .../notebooks/The_Four_Operations.doctree | Bin 39826 -> 0 bytes .../doctrees/notebooks/Treestep.doctree | Bin 48218 -> 0 bytes .../doctrees/notebooks/TypeChecking.doctree | Bin 9282 -> 0 bytes .../_build/doctrees/notebooks/Types.doctree | Bin 202626 -> 0 bytes .../_build/doctrees/notebooks/Zipper.doctree | Bin 33440 -> 0 bytes .../_build/doctrees/notebooks/index.doctree | Bin 4059 -> 0 bytes .../_build/doctrees/parser.doctree | Bin 13512 -> 0 bytes .../_build/doctrees/pretty.doctree | Bin 20801 -> 0 bytes .../sphinx_docs/_build/doctrees/stack.doctree | Bin 42921 -> 0 bytes .../sphinx_docs/_build/doctrees/types.doctree | Bin 16618 -> 0 bytes docs/sphinx_docs/_build/html/.buildinfo | 4 - docs/sphinx_docs/_build/html/_images/omg.svg | 185 - .../_build/html/_modules/index.html | 109 - .../_build/html/_modules/joy/joy.html | 255 - .../_build/html/_modules/joy/library.html | 1499 --- .../_build/html/_modules/joy/parser.html | 229 - .../_modules/joy/utils/generated_library.html | 519 - .../html/_modules/joy/utils/pretty_print.html | 229 - .../_build/html/_modules/joy/utils/stack.html | 377 - .../_build/html/_sources/index.rst.txt | 140 - .../_build/html/_sources/joy.rst.txt | 13 - .../_build/html/_sources/lib.rst.txt | 1761 --- .../_build/html/_sources/library.rst.txt | 19 - .../_sources/notebooks/Categorical.rst.txt | 17 - ...Derivatives_of_Regular_Expressions.rst.txt | 946 -- .../_sources/notebooks/Developing.rst.txt | 815 -- .../notebooks/Generator_Programs.rst.txt | 635 - .../html/_sources/notebooks/Intro.rst.txt | 335 - .../_sources/notebooks/Newton-Raphson.rst.txt | 257 - .../html/_sources/notebooks/NoUpdates.rst.txt | 22 - .../notebooks/Ordered_Binary_Trees.rst.txt | 1639 --- .../html/_sources/notebooks/Quadratic.rst.txt | 158 - .../notebooks/Recursion_Combinators.rst.txt | 690 - .../html/_sources/notebooks/Replacing.rst.txt | 147 - .../_sources/notebooks/Square_Spiral.rst.txt | 421 - .../notebooks/The_Four_Operations.rst.txt | 336 - .../html/_sources/notebooks/Treestep.rst.txt | 620 - .../_sources/notebooks/TypeChecking.rst.txt | 171 - .../html/_sources/notebooks/Types.rst.txt | 2968 ----- .../html/_sources/notebooks/Zipper.rst.txt | 352 - .../html/_sources/notebooks/index.rst.txt | 27 - .../_build/html/_sources/parser.rst.txt | 20 - .../_build/html/_sources/pretty.rst.txt | 13 - .../_build/html/_sources/stack.rst.txt | 13 - .../_build/html/_sources/types.rst.txt | 153 - .../_build/html/_static/alabaster.css | 701 - .../sphinx_docs/_build/html/_static/basic.css | 909 -- .../_build/html/_static/custom.css | 1 - .../_build/html/_static/doctools.js | 326 - .../html/_static/documentation_options.js | 12 - docs/sphinx_docs/_build/html/_static/file.png | Bin 286 -> 0 bytes .../_build/html/_static/jquery-3.5.1.js | 10872 ---------------- .../sphinx_docs/_build/html/_static/jquery.js | 2 - .../_build/html/_static/language_data.js | 297 - .../sphinx_docs/_build/html/_static/minus.png | Bin 90 -> 0 bytes docs/sphinx_docs/_build/html/_static/plus.png | Bin 90 -> 0 bytes .../_build/html/_static/pygments.css | 74 - .../_build/html/_static/searchtools.js | 529 - .../_build/html/_static/underscore-1.13.1.js | 2042 --- .../_build/html/_static/underscore-1.3.1.js | 999 -- .../_build/html/_static/underscore.js | 6 - docs/sphinx_docs/_build/html/genindex.html | 577 - docs/sphinx_docs/_build/html/index.html | 263 - docs/sphinx_docs/_build/html/joy.html | 192 - docs/sphinx_docs/_build/html/lib.html | 1340 -- docs/sphinx_docs/_build/html/library.html | 1071 -- .../_build/html/notebooks/Categorical.html | 138 - .../Derivatives_of_Regular_Expressions.html | 935 -- .../_build/html/notebooks/Developing.html | 755 -- .../html/notebooks/Generator_Programs.html | 584 - .../_build/html/notebooks/Intro.html | 376 - .../_build/html/notebooks/Newton-Raphson.html | 323 - .../_build/html/notebooks/NoUpdates.html | 151 - .../html/notebooks/Ordered_Binary_Trees.html | 1380 -- .../_build/html/notebooks/Quadratic.html | 260 - .../html/notebooks/Recursion_Combinators.html | 682 - .../_build/html/notebooks/Replacing.html | 258 - .../_build/html/notebooks/Square_Spiral.html | 463 - .../html/notebooks/The_Four_Operations.html | 411 - .../_build/html/notebooks/Treestep.html | 581 - .../_build/html/notebooks/TypeChecking.html | 247 - .../_build/html/notebooks/Types.html | 2472 ---- .../_build/html/notebooks/Zipper.html | 396 - .../_build/html/notebooks/index.html | 258 - docs/sphinx_docs/_build/html/objects.inv | Bin 1599 -> 0 bytes docs/sphinx_docs/_build/html/parser.html | 168 - docs/sphinx_docs/_build/html/pretty.html | 189 - docs/sphinx_docs/_build/html/py-modindex.html | 153 - docs/sphinx_docs/_build/html/search.html | 127 - docs/sphinx_docs/_build/html/searchindex.js | 1 - docs/sphinx_docs/_build/html/stack.html | 298 - docs/sphinx_docs/_build/html/types.html | 253 - docs/sphinx_docs/_static/basic.css | 909 -- docs/sphinx_docs/_templates/layout.html | 16 - docs/sphinx_docs/conf.py | 167 - docs/sphinx_docs/index.rst | 140 - docs/sphinx_docs/joy.rst | 13 - docs/sphinx_docs/lib.rst | 1761 --- docs/sphinx_docs/library.rst | 19 - docs/sphinx_docs/notebooks/Categorical.rst | 17 - .../Derivatives_of_Regular_Expressions.rst | 946 -- docs/sphinx_docs/notebooks/Developing.rst | 815 -- .../notebooks/Generator_Programs.rst | 635 - docs/sphinx_docs/notebooks/Intro.rst | 335 - docs/sphinx_docs/notebooks/Newton-Raphson.rst | 257 - docs/sphinx_docs/notebooks/NoUpdates.rst | 22 - .../notebooks/Ordered_Binary_Trees.rst | 1639 --- docs/sphinx_docs/notebooks/Quadratic.rst | 158 - .../notebooks/Recursion_Combinators.rst | 690 - docs/sphinx_docs/notebooks/Replacing.rst | 147 - docs/sphinx_docs/notebooks/Square_Spiral.rst | 421 - .../notebooks/The_Four_Operations.rst | 336 - docs/sphinx_docs/notebooks/Treestep.rst | 620 - docs/sphinx_docs/notebooks/TypeChecking.rst | 171 - docs/sphinx_docs/notebooks/Types.rst | 2968 ----- docs/sphinx_docs/notebooks/Zipper.rst | 352 - docs/sphinx_docs/notebooks/index.rst | 27 - docs/sphinx_docs/notebooks/omg.svg | 185 - docs/sphinx_docs/parser.rst | 20 - docs/sphinx_docs/pretty.rst | 13 - docs/sphinx_docs/stack.rst | 13 - docs/sphinx_docs/types.rst | 153 - docs/yow/AMPERSAND.md | 6 - docs/yow/AMPERSAND.rst | 42 - docs/yow/AMPERSAND•AMPERSAND.md | 29 - docs/yow/AMPERSAND•AMPERSAND.rst | 42 - docs/yow/ASTERISK.md | 6 - docs/yow/ASTERISK.rst | 42 - docs/yow/BULLET.md | 6 - docs/yow/BULLET.rst | 42 - docs/yow/CIRCUMFLEX-ACCENT.md | 6 - docs/yow/CIRCUMFLEX-ACCENT.rst | 42 - docs/yow/EQUALS-SIGN.md | 6 - docs/yow/EQUALS-SIGN.rst | 42 - docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.md | 6 - docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.rst | 42 - docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.md | 29 - docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.rst | 42 - docs/yow/GREATER-THAN-SIGN.md | 6 - docs/yow/GREATER-THAN-SIGN.rst | 42 - docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.md | 6 - docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.rst | 42 - .../GREATER-THAN-SIGN•GREATER-THAN-SIGN.md | 6 - .../GREATER-THAN-SIGN•GREATER-THAN-SIGN.rst | 42 - docs/yow/HYPHEN-MINUS.md | 6 - docs/yow/HYPHEN-MINUS.rst | 42 - docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.md | 6 - docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.rst | 42 - docs/yow/LESS-THAN-SIGN.md | 6 - docs/yow/LESS-THAN-SIGN.rst | 42 - docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.md | 6 - docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.rst | 42 - docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.md | 6 - docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.rst | 42 - ...•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md | 29 - ...LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst | 42 - docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.md | 6 - docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.rst | 42 - ...GN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md | 29 - ...N•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst | 42 - docs/yow/Makefile | 14 - docs/yow/PERCENT-SIGN.md | 6 - docs/yow/PERCENT-SIGN.rst | 42 - docs/yow/PLUS-SIGN.md | 6 - docs/yow/PLUS-SIGN.rst | 42 - docs/yow/PLUS-SIGN•PLUS-SIGN.md | 6 - docs/yow/PLUS-SIGN•PLUS-SIGN.rst | 42 - docs/yow/QUESTION-MARK.md | 29 - docs/yow/QUESTION-MARK.rst | 42 - docs/yow/SOLIDUS.md | 6 - docs/yow/SOLIDUS.rst | 42 - docs/yow/SOLIDUS•SOLIDUS.md | 6 - docs/yow/SOLIDUS•SOLIDUS.rst | 42 - docs/yow/SOLIDUS•floor.md | 6 - docs/yow/SOLIDUS•floor.rst | 42 - docs/yow/VERTICAL-LINE•VERTICAL-LINE.md | 29 - docs/yow/VERTICAL-LINE•VERTICAL-LINE.rst | 42 - docs/yow/abs.md | 29 - docs/yow/abs.rst | 42 - docs/yow/add.md | 29 - docs/yow/add.rst | 42 - docs/yow/aliassess.py | 148 - docs/yow/anamorphism.md | 29 - docs/yow/anamorphism.rst | 42 - docs/yow/and.md | 29 - docs/yow/and.rst | 42 - docs/yow/app2.md | 34 - docs/yow/app2.rst | 50 - docs/yow/app3.md | 35 - docs/yow/app3.rst | 51 - docs/yow/appN.md | 29 - docs/yow/appN.rst | 42 - docs/yow/at.md | 6 - docs/yow/at.rst | 55 - docs/yow/average.md | 29 - docs/yow/average.rst | 42 - docs/yow/bool.md | 33 - docs/yow/bool.rst | 46 - docs/yow/branch.md | 39 - docs/yow/branch.rst | 59 - docs/yow/ccccons.md | 29 - docs/yow/ccccons.rst | 42 - docs/yow/choice.md | 42 - docs/yow/choice.rst | 57 - docs/yow/clear.md | 34 - docs/yow/clear.rst | 50 - docs/yow/cleave.md | 29 - docs/yow/cleave.rst | 42 - docs/yow/clop.md | 29 - docs/yow/clop.rst | 42 - docs/yow/cmp.md | 42 - docs/yow/cmp.rst | 58 - docs/yow/codi.md | 29 - docs/yow/codi.rst | 42 - docs/yow/codireco.md | 29 - docs/yow/codireco.rst | 42 - docs/yow/concat.md | 33 - docs/yow/concat.rst | 50 - docs/yow/cond.md | 40 - docs/yow/cond.rst | 55 - docs/yow/dinfrirst.md | 29 - docs/yow/dinfrirst.rst | 42 - docs/yow/dip.md | 35 - docs/yow/dip.rst | 52 - docs/yow/dipd.md | 33 - docs/yow/dipd.rst | 50 - docs/yow/dipdd.md | 33 - docs/yow/dipdd.rst | 50 - docs/yow/disenstacken.md | 30 - docs/yow/disenstacken.rst | 45 - docs/yow/div.md | 6 - docs/yow/div.rst | 42 - docs/yow/divmod.md | 31 - docs/yow/divmod.rst | 46 - docs/yow/down_to_zero.md | 29 - docs/yow/down_to_zero.rst | 42 - docs/yow/drop.md | 36 - docs/yow/drop.rst | 55 - docs/yow/dup.md | 29 - docs/yow/dup.rst | 47 - docs/yow/dupd.md | 29 - docs/yow/dupd.rst | 47 - docs/yow/dupdd.md | 29 - docs/yow/dupdd.rst | 47 - docs/yow/dupdip.md | 34 - docs/yow/dupdip.rst | 52 - docs/yow/dupdipd.md | 29 - docs/yow/dupdipd.rst | 42 - docs/yow/enstacken.md | 29 - docs/yow/enstacken.rst | 42 - docs/yow/eq.md | 29 - docs/yow/eq.rst | 42 - docs/yow/first.md | 29 - docs/yow/first.rst | 47 - docs/yow/first_two.md | 29 - docs/yow/first_two.rst | 47 - docs/yow/flatten.md | 29 - docs/yow/flatten.rst | 42 - docs/yow/floor.md | 31 - docs/yow/floor.rst | 44 - docs/yow/floordiv.md | 29 - docs/yow/floordiv.rst | 42 - docs/yow/fork.md | 29 - docs/yow/fork.rst | 42 - docs/yow/fourth.md | 29 - docs/yow/fourth.rst | 47 - docs/yow/gcd.md | 29 - docs/yow/gcd.rst | 42 - docs/yow/gcd2.md | 29 - docs/yow/gcd2.rst | 42 - docs/yow/ge.md | 29 - docs/yow/ge.rst | 42 - docs/yow/genrec.md | 71 - docs/yow/genrec.rst | 92 - docs/yow/getitem.md | 36 - docs/yow/getitem.rst | 55 - docs/yow/grabN.md | 29 - docs/yow/grabN.rst | 42 - docs/yow/grba.md | 29 - docs/yow/grba.rst | 42 - docs/yow/gt.md | 29 - docs/yow/gt.rst | 42 - docs/yow/help.md | 29 - docs/yow/help.rst | 42 - docs/yow/hypot.md | 29 - docs/yow/hypot.rst | 42 - docs/yow/id.md | 29 - docs/yow/id.rst | 42 - docs/yow/ifte.md | 43 - docs/yow/ifte.rst | 60 - docs/yow/ii.md | 31 - docs/yow/ii.rst | 49 - docs/yow/infrst.md | 29 - docs/yow/infrst.rst | 42 - docs/yow/inscribe.md | 33 - docs/yow/inscribe.rst | 49 - docs/yow/le.md | 29 - docs/yow/le.rst | 42 - docs/yow/loop.md | 37 - docs/yow/loop.rst | 54 - docs/yow/lshift.md | 29 - docs/yow/lshift.rst | 42 - docs/yow/lt.md | 29 - docs/yow/lt.rst | 42 - docs/yow/make_generator.md | 29 - docs/yow/make_generator.rst | 42 - docs/yow/map.md | 30 - docs/yow/map.rst | 45 - docs/yow/max.md | 29 - docs/yow/max.rst | 42 - docs/yow/min.md | 29 - docs/yow/min.rst | 42 - docs/yow/mod.md | 29 - docs/yow/mod.rst | 42 - docs/yow/modulus.md | 6 - docs/yow/modulus.rst | 42 - docs/yow/mul.md | 29 - docs/yow/mul.rst | 42 - docs/yow/ne.md | 29 - docs/yow/ne.rst | 42 - docs/yow/neg.md | 29 - docs/yow/neg.rst | 42 - docs/yow/not.md | 29 - docs/yow/not.rst | 42 - docs/yow/nulco.md | 29 - docs/yow/nulco.rst | 42 - docs/yow/of.md | 29 - docs/yow/of.rst | 42 - docs/yow/or.md | 29 - docs/yow/or.rst | 42 - docs/yow/over.md | 29 - docs/yow/over.rst | 47 - docs/yow/pam.md | 29 - docs/yow/pam.rst | 42 - docs/yow/pick.md | 6 - docs/yow/pick.rst | 55 - docs/yow/pm.md | 33 - docs/yow/pm.rst | 50 - docs/yow/pop.md | 29 - docs/yow/pop.rst | 47 - docs/yow/popd.md | 29 - docs/yow/popd.rst | 47 - docs/yow/popdd.md | 29 - docs/yow/popdd.rst | 47 - docs/yow/popop.md | 29 - docs/yow/popop.rst | 47 - docs/yow/popopd.md | 29 - docs/yow/popopd.rst | 47 - docs/yow/popopdd.md | 29 - docs/yow/popopdd.rst | 47 - docs/yow/popopop.md | 29 - docs/yow/popopop.rst | 42 - docs/yow/pow.md | 29 - docs/yow/pow.rst | 42 - docs/yow/pred.md | 29 - docs/yow/pred.rst | 42 - docs/yow/primrec.md | 56 - docs/yow/primrec.rst | 72 - docs/yow/product.md | 29 - docs/yow/product.rst | 42 - docs/yow/quoted.md | 29 - docs/yow/quoted.rst | 42 - docs/yow/range.md | 29 - docs/yow/range.rst | 42 - docs/yow/range_to_zero.md | 29 - docs/yow/range_to_zero.rst | 42 - docs/yow/reco.md | 29 - docs/yow/reco.rst | 42 - docs/yow/rem.md | 6 - docs/yow/rem.rst | 42 - docs/yow/remainder.md | 6 - docs/yow/remainder.rst | 42 - docs/yow/remove.md | 35 - docs/yow/remove.rst | 52 - docs/yow/rest.md | 29 - docs/yow/rest.rst | 47 - docs/yow/reverse.md | 31 - docs/yow/reverse.rst | 47 - docs/yow/rolldown.md | 29 - docs/yow/rolldown.rst | 47 - docs/yow/rollup.md | 29 - docs/yow/rollup.rst | 47 - docs/yow/roll•GREATER-THAN-SIGN.md | 6 - docs/yow/roll•GREATER-THAN-SIGN.rst | 47 - docs/yow/roll•LESS-THAN-SIGN.md | 6 - docs/yow/roll•LESS-THAN-SIGN.rst | 47 - docs/yow/round.md | 33 - docs/yow/round.rst | 45 - docs/yow/rrest.md | 29 - docs/yow/rrest.rst | 47 - docs/yow/rshift.md | 29 - docs/yow/rshift.rst | 42 - docs/yow/run.md | 29 - docs/yow/run.rst | 42 - docs/yow/second.md | 29 - docs/yow/second.rst | 47 - docs/yow/select.md | 42 - docs/yow/select.rst | 58 - docs/yow/sharing.md | 29 - docs/yow/sharing.rst | 42 - docs/yow/shift.md | 29 - docs/yow/shift.rst | 42 - docs/yow/shunt.md | 35 - docs/yow/shunt.rst | 52 - docs/yow/size.md | 29 - docs/yow/size.rst | 42 - docs/yow/sort.md | 29 - docs/yow/sort.rst | 42 - docs/yow/spiral_next.md | 31 - docs/yow/spiral_next.rst | 42 - docs/yow/split_at.md | 29 - docs/yow/split_at.rst | 42 - docs/yow/split_list.md | 29 - docs/yow/split_list.rst | 42 - docs/yow/sqr.md | 29 - docs/yow/sqr.rst | 42 - docs/yow/sqrt.md | 30 - docs/yow/sqrt.rst | 45 - docs/yow/stack.md | 29 - docs/yow/stack.rst | 47 - docs/yow/stackd.md | 29 - docs/yow/stackd.rst | 42 - docs/yow/step.md | 46 - docs/yow/step.rst | 62 - docs/yow/step_zero.md | 29 - docs/yow/step_zero.rst | 42 - docs/yow/stuncons.md | 29 - docs/yow/stuncons.rst | 47 - docs/yow/stununcons.md | 29 - docs/yow/stununcons.rst | 47 - docs/yow/sub.md | 29 - docs/yow/sub.rst | 42 - docs/yow/succ.md | 29 - docs/yow/succ.rst | 42 - docs/yow/sum.md | 31 - docs/yow/sum.rst | 48 - docs/yow/swaack.md | 29 - docs/yow/swaack.rst | 47 - docs/yow/swap.md | 29 - docs/yow/swap.rst | 47 - docs/yow/swapd.md | 29 - docs/yow/swapd.rst | 42 - docs/yow/swoncat.md | 29 - docs/yow/swoncat.rst | 42 - docs/yow/swons.md | 29 - docs/yow/swons.rst | 47 - docs/yow/tailrec.md | 29 - docs/yow/tailrec.rst | 42 - docs/yow/take.md | 35 - docs/yow/take.rst | 52 - docs/yow/third.md | 29 - docs/yow/third.rst | 47 - docs/yow/times.md | 43 - docs/yow/times.rst | 60 - docs/yow/truthy.md | 6 - docs/yow/truthy.rst | 46 - docs/yow/tuck.md | 29 - docs/yow/tuck.rst | 47 - docs/yow/unique.md | 29 - docs/yow/unique.rst | 42 - docs/yow/unit.md | 29 - docs/yow/unit.rst | 47 - docs/yow/unquoted.md | 29 - docs/yow/unquoted.rst | 42 - docs/yow/unswons.md | 29 - docs/yow/unswons.rst | 47 - docs/yow/void.md | 29 - docs/yow/void.rst | 42 - docs/yow/warranty.md | 29 - docs/yow/warranty.rst | 42 - docs/yow/while.md | 29 - docs/yow/while.rst | 42 - docs/yow/words.md | 29 - docs/yow/words.rst | 42 - docs/yow/wrods.py | 127 - docs/yow/xor.md | 29 - docs/yow/xor.rst | 42 - docs/yow/zip.md | 30 - docs/yow/zip.rst | 45 - implementations/expr.py | 118 - 498 files changed, 75308 deletions(-) delete mode 100644 docs/sphinx_docs/Makefile delete mode 100644 docs/sphinx_docs/_build/doctrees/environment.pickle delete mode 100644 docs/sphinx_docs/_build/doctrees/index.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/joy.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/lib.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/library.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Categorical.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Derivatives_of_Regular_Expressions.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Developing.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Generator_Programs.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Intro.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Newton-Raphson.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/NoUpdates.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Ordered_Binary_Trees.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Quadratic.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Recursion_Combinators.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Square_Spiral.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/The_Four_Operations.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Treestep.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/TypeChecking.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Types.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/Zipper.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/notebooks/index.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/parser.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/pretty.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/stack.doctree delete mode 100644 docs/sphinx_docs/_build/doctrees/types.doctree delete mode 100644 docs/sphinx_docs/_build/html/.buildinfo delete mode 100644 docs/sphinx_docs/_build/html/_images/omg.svg delete mode 100644 docs/sphinx_docs/_build/html/_modules/index.html delete mode 100644 docs/sphinx_docs/_build/html/_modules/joy/joy.html delete mode 100644 docs/sphinx_docs/_build/html/_modules/joy/library.html delete mode 100644 docs/sphinx_docs/_build/html/_modules/joy/parser.html delete mode 100644 docs/sphinx_docs/_build/html/_modules/joy/utils/generated_library.html delete mode 100644 docs/sphinx_docs/_build/html/_modules/joy/utils/pretty_print.html delete mode 100644 docs/sphinx_docs/_build/html/_modules/joy/utils/stack.html delete mode 100644 docs/sphinx_docs/_build/html/_sources/index.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/joy.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/lib.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/library.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Categorical.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Developing.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Intro.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Newton-Raphson.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/NoUpdates.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Square_Spiral.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/The_Four_Operations.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/notebooks/index.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/parser.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/pretty.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/stack.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_sources/types.rst.txt delete mode 100644 docs/sphinx_docs/_build/html/_static/alabaster.css delete mode 100644 docs/sphinx_docs/_build/html/_static/basic.css delete mode 100644 docs/sphinx_docs/_build/html/_static/custom.css delete mode 100644 docs/sphinx_docs/_build/html/_static/doctools.js delete mode 100644 docs/sphinx_docs/_build/html/_static/documentation_options.js delete mode 100644 docs/sphinx_docs/_build/html/_static/file.png delete mode 100644 docs/sphinx_docs/_build/html/_static/jquery-3.5.1.js delete mode 100644 docs/sphinx_docs/_build/html/_static/jquery.js delete mode 100644 docs/sphinx_docs/_build/html/_static/language_data.js delete mode 100644 docs/sphinx_docs/_build/html/_static/minus.png delete mode 100644 docs/sphinx_docs/_build/html/_static/plus.png delete mode 100644 docs/sphinx_docs/_build/html/_static/pygments.css delete mode 100644 docs/sphinx_docs/_build/html/_static/searchtools.js delete mode 100644 docs/sphinx_docs/_build/html/_static/underscore-1.13.1.js delete mode 100644 docs/sphinx_docs/_build/html/_static/underscore-1.3.1.js delete mode 100644 docs/sphinx_docs/_build/html/_static/underscore.js delete mode 100644 docs/sphinx_docs/_build/html/genindex.html delete mode 100644 docs/sphinx_docs/_build/html/index.html delete mode 100644 docs/sphinx_docs/_build/html/joy.html delete mode 100644 docs/sphinx_docs/_build/html/lib.html delete mode 100644 docs/sphinx_docs/_build/html/library.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Categorical.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Derivatives_of_Regular_Expressions.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Developing.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Intro.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Newton-Raphson.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/NoUpdates.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Ordered_Binary_Trees.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Quadratic.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Recursion_Combinators.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Replacing.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Square_Spiral.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/The_Four_Operations.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Treestep.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/TypeChecking.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Types.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/Zipper.html delete mode 100644 docs/sphinx_docs/_build/html/notebooks/index.html delete mode 100644 docs/sphinx_docs/_build/html/objects.inv delete mode 100644 docs/sphinx_docs/_build/html/parser.html delete mode 100644 docs/sphinx_docs/_build/html/pretty.html delete mode 100644 docs/sphinx_docs/_build/html/py-modindex.html delete mode 100644 docs/sphinx_docs/_build/html/search.html delete mode 100644 docs/sphinx_docs/_build/html/searchindex.js delete mode 100644 docs/sphinx_docs/_build/html/stack.html delete mode 100644 docs/sphinx_docs/_build/html/types.html delete mode 100644 docs/sphinx_docs/_static/basic.css delete mode 100644 docs/sphinx_docs/_templates/layout.html delete mode 100644 docs/sphinx_docs/conf.py delete mode 100644 docs/sphinx_docs/index.rst delete mode 100644 docs/sphinx_docs/joy.rst delete mode 100644 docs/sphinx_docs/lib.rst delete mode 100644 docs/sphinx_docs/library.rst delete mode 100644 docs/sphinx_docs/notebooks/Categorical.rst delete mode 100644 docs/sphinx_docs/notebooks/Derivatives_of_Regular_Expressions.rst delete mode 100644 docs/sphinx_docs/notebooks/Developing.rst delete mode 100644 docs/sphinx_docs/notebooks/Generator_Programs.rst delete mode 100644 docs/sphinx_docs/notebooks/Intro.rst delete mode 100644 docs/sphinx_docs/notebooks/Newton-Raphson.rst delete mode 100644 docs/sphinx_docs/notebooks/NoUpdates.rst delete mode 100644 docs/sphinx_docs/notebooks/Ordered_Binary_Trees.rst delete mode 100644 docs/sphinx_docs/notebooks/Quadratic.rst delete mode 100644 docs/sphinx_docs/notebooks/Recursion_Combinators.rst delete mode 100644 docs/sphinx_docs/notebooks/Replacing.rst delete mode 100644 docs/sphinx_docs/notebooks/Square_Spiral.rst delete mode 100644 docs/sphinx_docs/notebooks/The_Four_Operations.rst delete mode 100644 docs/sphinx_docs/notebooks/Treestep.rst delete mode 100644 docs/sphinx_docs/notebooks/TypeChecking.rst delete mode 100644 docs/sphinx_docs/notebooks/Types.rst delete mode 100644 docs/sphinx_docs/notebooks/Zipper.rst delete mode 100644 docs/sphinx_docs/notebooks/index.rst delete mode 100644 docs/sphinx_docs/notebooks/omg.svg delete mode 100644 docs/sphinx_docs/parser.rst delete mode 100644 docs/sphinx_docs/pretty.rst delete mode 100644 docs/sphinx_docs/stack.rst delete mode 100644 docs/sphinx_docs/types.rst delete mode 100644 docs/yow/AMPERSAND.md delete mode 100644 docs/yow/AMPERSAND.rst delete mode 100644 docs/yow/AMPERSAND•AMPERSAND.md delete mode 100644 docs/yow/AMPERSAND•AMPERSAND.rst delete mode 100644 docs/yow/ASTERISK.md delete mode 100644 docs/yow/ASTERISK.rst delete mode 100644 docs/yow/BULLET.md delete mode 100644 docs/yow/BULLET.rst delete mode 100644 docs/yow/CIRCUMFLEX-ACCENT.md delete mode 100644 docs/yow/CIRCUMFLEX-ACCENT.rst delete mode 100644 docs/yow/EQUALS-SIGN.md delete mode 100644 docs/yow/EQUALS-SIGN.rst delete mode 100644 docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.md delete mode 100644 docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.rst delete mode 100644 docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.md delete mode 100644 docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.rst delete mode 100644 docs/yow/GREATER-THAN-SIGN.md delete mode 100644 docs/yow/GREATER-THAN-SIGN.rst delete mode 100644 docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.md delete mode 100644 docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.rst delete mode 100644 docs/yow/GREATER-THAN-SIGN•GREATER-THAN-SIGN.md delete mode 100644 docs/yow/GREATER-THAN-SIGN•GREATER-THAN-SIGN.rst delete mode 100644 docs/yow/HYPHEN-MINUS.md delete mode 100644 docs/yow/HYPHEN-MINUS.rst delete mode 100644 docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.md delete mode 100644 docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.rst delete mode 100644 docs/yow/LESS-THAN-SIGN.md delete mode 100644 docs/yow/LESS-THAN-SIGN.rst delete mode 100644 docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.md delete mode 100644 docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.rst delete mode 100644 docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.md delete mode 100644 docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.rst delete mode 100644 docs/yow/LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md delete mode 100644 docs/yow/LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst delete mode 100644 docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.md delete mode 100644 docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.rst delete mode 100644 docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md delete mode 100644 docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst delete mode 100644 docs/yow/Makefile delete mode 100644 docs/yow/PERCENT-SIGN.md delete mode 100644 docs/yow/PERCENT-SIGN.rst delete mode 100644 docs/yow/PLUS-SIGN.md delete mode 100644 docs/yow/PLUS-SIGN.rst delete mode 100644 docs/yow/PLUS-SIGN•PLUS-SIGN.md delete mode 100644 docs/yow/PLUS-SIGN•PLUS-SIGN.rst delete mode 100644 docs/yow/QUESTION-MARK.md delete mode 100644 docs/yow/QUESTION-MARK.rst delete mode 100644 docs/yow/SOLIDUS.md delete mode 100644 docs/yow/SOLIDUS.rst delete mode 100644 docs/yow/SOLIDUS•SOLIDUS.md delete mode 100644 docs/yow/SOLIDUS•SOLIDUS.rst delete mode 100644 docs/yow/SOLIDUS•floor.md delete mode 100644 docs/yow/SOLIDUS•floor.rst delete mode 100644 docs/yow/VERTICAL-LINE•VERTICAL-LINE.md delete mode 100644 docs/yow/VERTICAL-LINE•VERTICAL-LINE.rst delete mode 100644 docs/yow/abs.md delete mode 100644 docs/yow/abs.rst delete mode 100644 docs/yow/add.md delete mode 100644 docs/yow/add.rst delete mode 100644 docs/yow/aliassess.py delete mode 100644 docs/yow/anamorphism.md delete mode 100644 docs/yow/anamorphism.rst delete mode 100644 docs/yow/and.md delete mode 100644 docs/yow/and.rst delete mode 100644 docs/yow/app2.md delete mode 100644 docs/yow/app2.rst delete mode 100644 docs/yow/app3.md delete mode 100644 docs/yow/app3.rst delete mode 100644 docs/yow/appN.md delete mode 100644 docs/yow/appN.rst delete mode 100644 docs/yow/at.md delete mode 100644 docs/yow/at.rst delete mode 100644 docs/yow/average.md delete mode 100644 docs/yow/average.rst delete mode 100644 docs/yow/bool.md delete mode 100644 docs/yow/bool.rst delete mode 100644 docs/yow/branch.md delete mode 100644 docs/yow/branch.rst delete mode 100644 docs/yow/ccccons.md delete mode 100644 docs/yow/ccccons.rst delete mode 100644 docs/yow/choice.md delete mode 100644 docs/yow/choice.rst delete mode 100644 docs/yow/clear.md delete mode 100644 docs/yow/clear.rst delete mode 100644 docs/yow/cleave.md delete mode 100644 docs/yow/cleave.rst delete mode 100644 docs/yow/clop.md delete mode 100644 docs/yow/clop.rst delete mode 100644 docs/yow/cmp.md delete mode 100644 docs/yow/cmp.rst delete mode 100644 docs/yow/codi.md delete mode 100644 docs/yow/codi.rst delete mode 100644 docs/yow/codireco.md delete mode 100644 docs/yow/codireco.rst delete mode 100644 docs/yow/concat.md delete mode 100644 docs/yow/concat.rst delete mode 100644 docs/yow/cond.md delete mode 100644 docs/yow/cond.rst delete mode 100644 docs/yow/dinfrirst.md delete mode 100644 docs/yow/dinfrirst.rst delete mode 100644 docs/yow/dip.md delete mode 100644 docs/yow/dip.rst delete mode 100644 docs/yow/dipd.md delete mode 100644 docs/yow/dipd.rst delete mode 100644 docs/yow/dipdd.md delete mode 100644 docs/yow/dipdd.rst delete mode 100644 docs/yow/disenstacken.md delete mode 100644 docs/yow/disenstacken.rst delete mode 100644 docs/yow/div.md delete mode 100644 docs/yow/div.rst delete mode 100644 docs/yow/divmod.md delete mode 100644 docs/yow/divmod.rst delete mode 100644 docs/yow/down_to_zero.md delete mode 100644 docs/yow/down_to_zero.rst delete mode 100644 docs/yow/drop.md delete mode 100644 docs/yow/drop.rst delete mode 100644 docs/yow/dup.md delete mode 100644 docs/yow/dup.rst delete mode 100644 docs/yow/dupd.md delete mode 100644 docs/yow/dupd.rst delete mode 100644 docs/yow/dupdd.md delete mode 100644 docs/yow/dupdd.rst delete mode 100644 docs/yow/dupdip.md delete mode 100644 docs/yow/dupdip.rst delete mode 100644 docs/yow/dupdipd.md delete mode 100644 docs/yow/dupdipd.rst delete mode 100644 docs/yow/enstacken.md delete mode 100644 docs/yow/enstacken.rst delete mode 100644 docs/yow/eq.md delete mode 100644 docs/yow/eq.rst delete mode 100644 docs/yow/first.md delete mode 100644 docs/yow/first.rst delete mode 100644 docs/yow/first_two.md delete mode 100644 docs/yow/first_two.rst delete mode 100644 docs/yow/flatten.md delete mode 100644 docs/yow/flatten.rst delete mode 100644 docs/yow/floor.md delete mode 100644 docs/yow/floor.rst delete mode 100644 docs/yow/floordiv.md delete mode 100644 docs/yow/floordiv.rst delete mode 100644 docs/yow/fork.md delete mode 100644 docs/yow/fork.rst delete mode 100644 docs/yow/fourth.md delete mode 100644 docs/yow/fourth.rst delete mode 100644 docs/yow/gcd.md delete mode 100644 docs/yow/gcd.rst delete mode 100644 docs/yow/gcd2.md delete mode 100644 docs/yow/gcd2.rst delete mode 100644 docs/yow/ge.md delete mode 100644 docs/yow/ge.rst delete mode 100644 docs/yow/genrec.md delete mode 100644 docs/yow/genrec.rst delete mode 100644 docs/yow/getitem.md delete mode 100644 docs/yow/getitem.rst delete mode 100644 docs/yow/grabN.md delete mode 100644 docs/yow/grabN.rst delete mode 100644 docs/yow/grba.md delete mode 100644 docs/yow/grba.rst delete mode 100644 docs/yow/gt.md delete mode 100644 docs/yow/gt.rst delete mode 100644 docs/yow/help.md delete mode 100644 docs/yow/help.rst delete mode 100644 docs/yow/hypot.md delete mode 100644 docs/yow/hypot.rst delete mode 100644 docs/yow/id.md delete mode 100644 docs/yow/id.rst delete mode 100644 docs/yow/ifte.md delete mode 100644 docs/yow/ifte.rst delete mode 100644 docs/yow/ii.md delete mode 100644 docs/yow/ii.rst delete mode 100644 docs/yow/infrst.md delete mode 100644 docs/yow/infrst.rst delete mode 100644 docs/yow/inscribe.md delete mode 100644 docs/yow/inscribe.rst delete mode 100644 docs/yow/le.md delete mode 100644 docs/yow/le.rst delete mode 100644 docs/yow/loop.md delete mode 100644 docs/yow/loop.rst delete mode 100644 docs/yow/lshift.md delete mode 100644 docs/yow/lshift.rst delete mode 100644 docs/yow/lt.md delete mode 100644 docs/yow/lt.rst delete mode 100644 docs/yow/make_generator.md delete mode 100644 docs/yow/make_generator.rst delete mode 100644 docs/yow/map.md delete mode 100644 docs/yow/map.rst delete mode 100644 docs/yow/max.md delete mode 100644 docs/yow/max.rst delete mode 100644 docs/yow/min.md delete mode 100644 docs/yow/min.rst delete mode 100644 docs/yow/mod.md delete mode 100644 docs/yow/mod.rst delete mode 100644 docs/yow/modulus.md delete mode 100644 docs/yow/modulus.rst delete mode 100644 docs/yow/mul.md delete mode 100644 docs/yow/mul.rst delete mode 100644 docs/yow/ne.md delete mode 100644 docs/yow/ne.rst delete mode 100644 docs/yow/neg.md delete mode 100644 docs/yow/neg.rst delete mode 100644 docs/yow/not.md delete mode 100644 docs/yow/not.rst delete mode 100644 docs/yow/nulco.md delete mode 100644 docs/yow/nulco.rst delete mode 100644 docs/yow/of.md delete mode 100644 docs/yow/of.rst delete mode 100644 docs/yow/or.md delete mode 100644 docs/yow/or.rst delete mode 100644 docs/yow/over.md delete mode 100644 docs/yow/over.rst delete mode 100644 docs/yow/pam.md delete mode 100644 docs/yow/pam.rst delete mode 100644 docs/yow/pick.md delete mode 100644 docs/yow/pick.rst delete mode 100644 docs/yow/pm.md delete mode 100644 docs/yow/pm.rst delete mode 100644 docs/yow/pop.md delete mode 100644 docs/yow/pop.rst delete mode 100644 docs/yow/popd.md delete mode 100644 docs/yow/popd.rst delete mode 100644 docs/yow/popdd.md delete mode 100644 docs/yow/popdd.rst delete mode 100644 docs/yow/popop.md delete mode 100644 docs/yow/popop.rst delete mode 100644 docs/yow/popopd.md delete mode 100644 docs/yow/popopd.rst delete mode 100644 docs/yow/popopdd.md delete mode 100644 docs/yow/popopdd.rst delete mode 100644 docs/yow/popopop.md delete mode 100644 docs/yow/popopop.rst delete mode 100644 docs/yow/pow.md delete mode 100644 docs/yow/pow.rst delete mode 100644 docs/yow/pred.md delete mode 100644 docs/yow/pred.rst delete mode 100644 docs/yow/primrec.md delete mode 100644 docs/yow/primrec.rst delete mode 100644 docs/yow/product.md delete mode 100644 docs/yow/product.rst delete mode 100644 docs/yow/quoted.md delete mode 100644 docs/yow/quoted.rst delete mode 100644 docs/yow/range.md delete mode 100644 docs/yow/range.rst delete mode 100644 docs/yow/range_to_zero.md delete mode 100644 docs/yow/range_to_zero.rst delete mode 100644 docs/yow/reco.md delete mode 100644 docs/yow/reco.rst delete mode 100644 docs/yow/rem.md delete mode 100644 docs/yow/rem.rst delete mode 100644 docs/yow/remainder.md delete mode 100644 docs/yow/remainder.rst delete mode 100644 docs/yow/remove.md delete mode 100644 docs/yow/remove.rst delete mode 100644 docs/yow/rest.md delete mode 100644 docs/yow/rest.rst delete mode 100644 docs/yow/reverse.md delete mode 100644 docs/yow/reverse.rst delete mode 100644 docs/yow/rolldown.md delete mode 100644 docs/yow/rolldown.rst delete mode 100644 docs/yow/rollup.md delete mode 100644 docs/yow/rollup.rst delete mode 100644 docs/yow/roll•GREATER-THAN-SIGN.md delete mode 100644 docs/yow/roll•GREATER-THAN-SIGN.rst delete mode 100644 docs/yow/roll•LESS-THAN-SIGN.md delete mode 100644 docs/yow/roll•LESS-THAN-SIGN.rst delete mode 100644 docs/yow/round.md delete mode 100644 docs/yow/round.rst delete mode 100644 docs/yow/rrest.md delete mode 100644 docs/yow/rrest.rst delete mode 100644 docs/yow/rshift.md delete mode 100644 docs/yow/rshift.rst delete mode 100644 docs/yow/run.md delete mode 100644 docs/yow/run.rst delete mode 100644 docs/yow/second.md delete mode 100644 docs/yow/second.rst delete mode 100644 docs/yow/select.md delete mode 100644 docs/yow/select.rst delete mode 100644 docs/yow/sharing.md delete mode 100644 docs/yow/sharing.rst delete mode 100644 docs/yow/shift.md delete mode 100644 docs/yow/shift.rst delete mode 100644 docs/yow/shunt.md delete mode 100644 docs/yow/shunt.rst delete mode 100644 docs/yow/size.md delete mode 100644 docs/yow/size.rst delete mode 100644 docs/yow/sort.md delete mode 100644 docs/yow/sort.rst delete mode 100644 docs/yow/spiral_next.md delete mode 100644 docs/yow/spiral_next.rst delete mode 100644 docs/yow/split_at.md delete mode 100644 docs/yow/split_at.rst delete mode 100644 docs/yow/split_list.md delete mode 100644 docs/yow/split_list.rst delete mode 100644 docs/yow/sqr.md delete mode 100644 docs/yow/sqr.rst delete mode 100644 docs/yow/sqrt.md delete mode 100644 docs/yow/sqrt.rst delete mode 100644 docs/yow/stack.md delete mode 100644 docs/yow/stack.rst delete mode 100644 docs/yow/stackd.md delete mode 100644 docs/yow/stackd.rst delete mode 100644 docs/yow/step.md delete mode 100644 docs/yow/step.rst delete mode 100644 docs/yow/step_zero.md delete mode 100644 docs/yow/step_zero.rst delete mode 100644 docs/yow/stuncons.md delete mode 100644 docs/yow/stuncons.rst delete mode 100644 docs/yow/stununcons.md delete mode 100644 docs/yow/stununcons.rst delete mode 100644 docs/yow/sub.md delete mode 100644 docs/yow/sub.rst delete mode 100644 docs/yow/succ.md delete mode 100644 docs/yow/succ.rst delete mode 100644 docs/yow/sum.md delete mode 100644 docs/yow/sum.rst delete mode 100644 docs/yow/swaack.md delete mode 100644 docs/yow/swaack.rst delete mode 100644 docs/yow/swap.md delete mode 100644 docs/yow/swap.rst delete mode 100644 docs/yow/swapd.md delete mode 100644 docs/yow/swapd.rst delete mode 100644 docs/yow/swoncat.md delete mode 100644 docs/yow/swoncat.rst delete mode 100644 docs/yow/swons.md delete mode 100644 docs/yow/swons.rst delete mode 100644 docs/yow/tailrec.md delete mode 100644 docs/yow/tailrec.rst delete mode 100644 docs/yow/take.md delete mode 100644 docs/yow/take.rst delete mode 100644 docs/yow/third.md delete mode 100644 docs/yow/third.rst delete mode 100644 docs/yow/times.md delete mode 100644 docs/yow/times.rst delete mode 100644 docs/yow/truthy.md delete mode 100644 docs/yow/truthy.rst delete mode 100644 docs/yow/tuck.md delete mode 100644 docs/yow/tuck.rst delete mode 100644 docs/yow/unique.md delete mode 100644 docs/yow/unique.rst delete mode 100644 docs/yow/unit.md delete mode 100644 docs/yow/unit.rst delete mode 100644 docs/yow/unquoted.md delete mode 100644 docs/yow/unquoted.rst delete mode 100644 docs/yow/unswons.md delete mode 100644 docs/yow/unswons.rst delete mode 100644 docs/yow/void.md delete mode 100644 docs/yow/void.rst delete mode 100644 docs/yow/warranty.md delete mode 100644 docs/yow/warranty.rst delete mode 100644 docs/yow/while.md delete mode 100644 docs/yow/while.rst delete mode 100644 docs/yow/words.md delete mode 100644 docs/yow/words.rst delete mode 100644 docs/yow/wrods.py delete mode 100644 docs/yow/xor.md delete mode 100644 docs/yow/xor.rst delete mode 100644 docs/yow/zip.md delete mode 100644 docs/yow/zip.rst delete mode 100644 implementations/expr.py diff --git a/docs/sphinx_docs/Makefile b/docs/sphinx_docs/Makefile deleted file mode 100644 index 9602036..0000000 --- a/docs/sphinx_docs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXPROJ = Thun -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/sphinx_docs/_build/doctrees/environment.pickle b/docs/sphinx_docs/_build/doctrees/environment.pickle deleted file mode 100644 index 1f9dd0df086d26d516b61e751da4c7cb5e727651..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 292656 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 diff --git a/docs/sphinx_docs/_build/doctrees/index.doctree b/docs/sphinx_docs/_build/doctrees/index.doctree deleted file mode 100644 index bca829d2a7b34a8a8928c41939cae55c5cef37b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23882 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 diff --git a/docs/sphinx_docs/_build/doctrees/joy.doctree b/docs/sphinx_docs/_build/doctrees/joy.doctree deleted file mode 100644 index a3e0fc8911899f12cd1dda7f3ae4585ee6e121df..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26671 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 diff --git a/docs/sphinx_docs/_build/doctrees/lib.doctree b/docs/sphinx_docs/_build/doctrees/lib.doctree deleted file mode 100644 index 66ed7a51e710074677553e802830a8887a3902e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 95615 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 UkS9AbNA7#*>C&jOJv;V)0EK3&HUIzs diff --git a/docs/sphinx_docs/_build/doctrees/library.doctree b/docs/sphinx_docs/_build/doctrees/library.doctree deleted file mode 100644 index 49aebd89302f3da7f1bfd0f80efff8e204e7a605..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 223865 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 diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Categorical.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Categorical.doctree deleted file mode 100644 index f9267f355d8609089f0cf3aec7a4effb84052b2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7668 zcmeHMTZV%}yqhl9<%Zn+u(~b>e%&dTiry#x!ajFmrj3eu z%6?_^%y2lc08-YbPdJ&+WKpk&&@b z=H=UG%L!~TfOZ@PDrDb+>p#D9>z%u`y{`DCwKB>NAl3-q;rM+(ReKK(L&8tAri$$+RVn( zYV}w~P6}<7Kf51A?Wqo6I)RgdN3~vt^Sc?&{EFY|ZBlib9PfsB`%k8oKU*Kodwv7E zmPS>6cq+kzU2b8+pFXMa&OOR__x|iw_u>0^0 z7VC_>IAIIrB-1dSVbd}XL4_Dec|I%oOxW7|u>NAP7|q3@%6U35B9?B1CB`wrdHj)H z4l`wpHsg<8e>2YANV+VglVDOXZs&H7UE9}XnlS9stL_enIG|w5H+Z0PBOyy29-mOdVz8b&Bto}L?lA0`-l@@Ax+<)W1!TbW#5S5b(;qn+V=j%zXLaPfw%fR8jNg zgFmm_$DE*%ACG-Cki9`uJR9^n&f+%BVB zxN*S?VJteD2}7rcs|n+9x9rns_I8>o?Hrq_L)==^dx)i5J>y5FYPy@+T)kH<6mz8?1@jH1Fi=I zT>cIAZBApwy1w1~lPC6M4!YfQ(1G8Yq&l8QAD3XpeVQ1ui4`fmcWn*4$}wEp3z4S7 zd9D{ZC_!*C!K}&(5C*pdJ8gIh{56fsw8UL+Sq7ez;?rcwIG9WfE+(u3dx=v`q^I%i zCA+@Azkg!{%7#g?HXu5M&J*IW;2ARzGH1!vLkxw@dZevoOGGQUQNk@L5Wt9p0b_EU z5++bF!DHE5y9r0m5;YBU*>%!@vtVF;C~}2-hb=fX)XWH;s^5Zjk&G%4oD}3lW@4SD zbzVjrQ^aBMA+a@KYLSVkg)Ak=!jKR`d17oin3uAF^wmKx4A@!;NwM-T-rWzJ>RoV2 z7{4)3zzBwPGDdm@R#uPB86Ab7+%hPPr4tOwpgL$GtPT=piD`xvzs^#yT%48(*++7d zEI^l8tV|5L2P^W@=?pu>E4!(%;U3L1wE!thk`-kw3FbhQa2$sKE)MisT4hJHt$QCJ}2rEN`HH@`@CO3*~PTKepA8VFYSd_S6xt@>D_DFAj!X>YfK7c ziixK12cEYnH8q>On{XTGStr;Eb*&?PzT@3)3hz`Lnuj~@C?NeI@+1tuCNKF1eth4gi zf5NN&ae9xv*g9i5S=aXc%~*s8aQu=X6y^G&lfDOx*D#}O5P=_|Hdhg@b^`O8zS9o2Dr zA8$Y7cc>zsmsxZ~aay5g7lcO@5w3M2Ll#TESoeU5hMtIOe^Fb8#*WQ|rY?Qpw~Z*Y zaZ#vERkxq@=Ou!-ZLa%E;B2rJ=uK%?z3YjXlrwC%3(7~(`=n5)@;faBg1Hm4pT)a{e-3q0ZIUPv1)Kxh z0G?ok4N&SSbc8un5`i60)lnrk{4P<-Xw~JPRq&{tq|Az_^Ey~HbOfdd21yHE2t5I@ z14egUg%xF@qoa)c=_2Z&0NSWOGq_0XqC;g>?VlH-L|Lk4LXk$w%{Ch3p5KNt#L@%P z#iBdSuxP5%`T^q#{lX@o{KWBbytG<^^WMS(PuGNhUZRkK+vGENVX89as`oFx=64HG zL|x^c^xLMM35VHlhRk^X*0M%cFQsQKF`<%ZD$IPNG zMmt3!Tac$b^cU?CsmW0!QI<%lG*RKTNR$6>+YEVOor+o*?77emnJL0c0~%`+UyYHE z@E8=m4mwynm=d$+Wq~c|xh%YaHDK@%UZi7{PvHwKI$S2au;t|Vxb494Bb8C@pMa2guFXZRe z52%Cka{4U4II!{+{QtS!wtlC7N@4a+j8cBs9xK*86qN0_TFibAc~I!Zsb&+Mb_X9i zzjLCq8$CF-;-K9%OuBq*eSoWRgyzqmT&wwV#-9gd#JZ$3zw%qF92|GXChEtb|1&86 zNp%Nqk5?ZA5?&i^IAT0LUha_NSoc=f9gb|P&V~`NdPYx{=Mw_A1_$WEEhnR|0QbB| AWdHyG 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 deleted file mode 100644 index 3bd734264ed0ddc3390af73b827a71a097f7bd2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67567 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 Bls5nX diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Developing.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Developing.doctree deleted file mode 100644 index 8bfaf107e71a67d53844cd4b6880042579ae7205..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66685 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 diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Intro.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Intro.doctree deleted file mode 100644 index 14627f9183cad7eeefd5121d664a710dd4e372d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40975 zcmeHweT*FEd7miqc)a1aXfl;)Nw1EPc%-;{BxTj|>B}TV#k8msEuJN+*X!==?(FUC z&F-vcW_foG>MAXaTIi%ks!dY2X<@Ya$AQzvNs}NgP{2ltHffEbHJqjhV6-mU{Lut; z5)?&(rs?l_-g!S}Z*O<+j#MO>6tuTH^L{_y&-=X3`_{xy?)l1n{4YHmcN%_st?1Tj z?Xc#>y>wqKtae*oJL$dCJM&|`zuKEgry_SX4!cp+>!tUhM77}uwa9DtmU`(SDxUa3 zT+HfE#$Gk?!?v#8m}u;6OfL0i8dK>+;wOP;y-JTQG`j6M@u_fK_-%1xJ!zmS6-Vhk z3*H(HV{oA_^mue={#d%V<6=BXuW>Y;D(ML{cBgx@anGlF0>AC`=DQU)b=)M0{7N^$ zd})5W{aQ?OnXCqG9OEIrPqf{Z{I;*w?U)}Gx4IH}bt=UiBJ>8z&nF8Xsxw zZakEJVzwJcvyHIj&BpaGYPs#%II7NKiks0#lfmyBxWlhP`HATWI*P@LQe0BS5*d+yYNpp4(1@8w*z?VHgN>F1)o) z5JrA`StJclbfOTgwOaV?v;glwxa}J1VbyCQtP>cD84yJ5d97Fk{)&h8mLtzi`nq%i zx4qnTmp$%?AV?j?-fb^(1Az*0*p7=5m?zTr*Psn@T>xZfC1mFt4-@`09s$xc9tDb? z!vBxq|I_&Y3=pF6M5EAnsBsSP+p7?Q;kduj4FWGI1wNpw=*lLHDSA`#6R%~xPJiMJ zPgLEu2mn|C7!wF3i2xL>ZsJw~PbBLdFXp8OiHeFF`&9q|SeN)!paS5_CFVe1NqkP! zgV3eFF-V}jj4xcG3tYnY)rMbf2(Jx5R;kf$n`s%~>~tePS=aTL5SqtFYoZGt=Sqj5#8PI?OPTlNyM>_!!$lWGVo;1y+f)g#Z_ zu%b)ZijGy+%y9|hC~bX?`%!IiM|1q4D`BhS2a*Zh_FZv>dH9BTCE2_-EpO(MU{JTW zK9>Wi7VT&*Zz|#<7COBgbUmSX+_YHrlZF8C)MDb4fnSN-$On-~npu^Ux(Z%Rf{eLg zMm=%SaU>Vibd$bumwHm%cF}JCdvEmTf7Ha!EWFJZ}leCv=ph-zDMe(eeCMR$DTg_*vFsr(1iZcp{7a! zntHxmDoNNts6&77psqljvP8i@$>`(ckdc^`Plp!6q)j zcfJw~o?pNSzcva1NT>R$oCb^3qky5IpntvqVc2p(Ypd=$^c@m!P&}%ML~Rn4M1=gb z6M1+?DpJyj!tQbd2brE&jZLNJlcZ3+2V?>x~ zoJe1~Gjp)e;!d@QrTrQV#&+4|)%MI0F4RC+Lg>Ikj7R0+cBip5rLRd(HX-w%rp z%j73Tp(UE(x>y) z!+L^uo>V@GUhqS#dI9x9v>buMl7dP$n(z~++pd9rt6qfG+Zao`=9AGAKa+J7Hz14K z%hUE4&?huw3?htb@iesxiw1;Gnl?#rHwXm3lcShke3n?@^Gl-P1syKW?3%wbw zlJzqr0;(%T=S^TY*>Et_QJ+K-EPkmiLsn2#kQi#P9p;KTpxRtHfgtm!X;LS;vh=gX z;w%ZWWc~Rv2r&qp3e_b6R|9SaLAZ)95INK)cg{_!)|Wv!b4K*+q3PNDmVY-+Hg|zx z*en;^WisO~7GFuH^wKB}KEX?6nk3jX5A?ORIRgiCYdTa~4uRRO|E?{&8Fu`H%;qUtU~;aVNRJJ`F|!H`ywgL0HQ`Y8SkrBu=~se$xxpHHmEDswF)ZLin7h<4IRlqI)D zFWt>m_Tx9Xy8No2^uEZiAz<40O4>G*F___KMw1XRfaW7KFzK#&+(x^nw@Y4T{nG8X zF#svXQwcB!sV{?ezOU7_M_EE$d{V@pjl_kg#S@P6)JH!iEb*lXc#M)c#@qb#2#7ZR zta%?5fm=-R+OyUe4X=F!%m)ep)B{&Y-d84tqvE&SB#bPswcjdeEq3lP)~`f>WoN8( z*@1^0X3ukp(4^n=N++{E)j~`#X_)qz7@B=;4(DVIDlG@Xoa}%-AJcN0e?DO7;E$@;XPZFKi{Ta;}vm_D^5Nh6KFWR3h<~y(n`;OWj-gqR+v|(riGA zx)@>*F7DX-Y?u5cQrjm*i1i!jL0CFc=~xGX>VrZ-NR`OISCzuL1Jw(A85kU#cGVRR z8eF-&SS%Ko%H^V9J4cr$sY0Bn8$+97QzYxbsf2IXCiu7MpF#E8sAJ3TJgEBh%gkyZG~;#n%v~XAGsN^RbueJ{EVtX!8u2> zEn(G0Es>BCZ{3QilTLxT7g)|%5}Y1N{y$t^lY|^1uf>gS)!EQCd zt5^YTbV0p3&Exm8&UuXfSjz8E;$i82MAu;H{<1CI)8D`BRb2=}c3tptK)^v+XGs-y z*_D=UHc44UB66LJ=sjvkd0B~84^kA45LJbh18km6SHdU?SEUCJUJ`6jhwP#wk4Y`J zHr#d@8`89b))w^$Nh_DUWGa-X*^*v!lD|gI{=Ii++SrK6I_)Vnjv ztpcY9ntD_tRc3>k9fa5K4)7Gs9NmB#)`|^yiNT)j8|>yZqZr?ycD|WDKb!%MLP5`T|4l!bgu?%5~ zClGiTs&RRdzMlIpvu%ks58=r#Lwj;u+AAQSxCEG+9Bi+zo3jsljal6q!1 zO_||phMZatvHJa^91b_Kx?a^oV!r(8;mddEQd?XjCo?&Ty+}>A|FIrkbDf$$*<97V zj1%8P<4SZ59@hfKrLDpAPxDYDb1xf_ULvxQ5ZM`LQXoenBr@W({ozS^sul zBV!>e^~}in{oJm&qO%V&R5a43KX`Ko!S>_aaMq(VTA; zI&wctBi1oQBD`6K$pDg+J79$yh|VSYyqT=SDKtXe%hl}2no#yo)5PLvm8AL4h@hk| z;lsI_xjv1^NQafey8X)71gaE@p$&dBeR{ZNksEVvwpyq7MJE5DoPw=^f2xPh+mVl>>g#-S49-ZY z`CY1UCrF0o%@XrFA4t5j7W)G_!2!6tE#u(##>PR*IMCSRXf9=2bN15#;~Y;$mrzqN z?3|4LaMhNanM8m)3-ZsB*8@vI_m-vdrd+@5Cc!X7b{~A*_g3}96^-{j)p}X;f!%D3 z9HBp3a$X(OHCS9Va^mV2Ag&e$T9ui&fY`vviVi9JIOI?+-^QT52-YVe2KW>div@=_ zb(E;dBEDgDNG=}2Msaa$LfRl?He}1q5&;~ajwV@~MwUowb`gtK@!#%`fEs+Iady?b@2q^2kn_o zSWw39ZI)aiY?ye3Dqt^-Vo#h9r+9e$Z7*R_2U!KbB-R8W@#u)gXzzqslS)DaTR`+V zgn|g!&_Wdw7y3XJFa-$iEd{huG!YgTv<5`W(OXCp<9 zCybk*WhIVs!uTN3tM;&3@|Ry|Rx;9DCgCy z%cx+Nn)GqZH}>dIF)IYrgfxTY;Zi3+tfUM-p;uWPs^v!≫(SIekW*O66k&2G#Dr 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 diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Newton-Raphson.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Newton-Raphson.doctree deleted file mode 100644 index 690f96e3d757e1db581af34b54915fd9f17ff0ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21438 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 AFaQ7m diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/NoUpdates.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/NoUpdates.doctree deleted file mode 100644 index 2210df9e76e0603c02a9d83b14077b9f76b6d775..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8543 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 diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Quadratic.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Quadratic.doctree deleted file mode 100644 index f3e6e769cd5d186f111ebe1d6e640fd643325e98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20427 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 OQ_lPstre1H?SBD>GDeL6 diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Recursion_Combinators.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Recursion_Combinators.doctree deleted file mode 100644 index f44277e097842ac03c55c5dbc1bc29faf1b2beef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70381 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 YP{B0fE|U%^RA|Z#XD6}*yQQiB51Xpr#sB~S diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Replacing.doctree deleted file mode 100644 index af1b3bcd12ff576cae36284173b08a33e51edeae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30625 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 UY>-{BrjZ#vu{e_nD_n2<4;BKWS^xk5 diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Square_Spiral.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Square_Spiral.doctree deleted file mode 100644 index 32f73e81c8c6c68a8e4478965e7f2b528a95f31c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45962 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 KNA^TxzVQFg!%u4f diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/The_Four_Operations.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/The_Four_Operations.doctree deleted file mode 100644 index d232c6e2cfdb26ee640b4e902226b99e99d9be14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39826 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 diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/TypeChecking.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/TypeChecking.doctree deleted file mode 100644 index c0f5ebb39612f65234721c42a5c55f48e2a3e289..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9282 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 au5WpX4JZgYlm{rS12!{+q18NTHU0&)BdUJ@ diff --git a/docs/sphinx_docs/_build/doctrees/notebooks/Types.doctree b/docs/sphinx_docs/_build/doctrees/notebooks/Types.doctree deleted file mode 100644 index 2709a75384af1caca59f88b730387a2b8a9d9e5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202626 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 TNcq)Ur12BwNRCK+_LVe>8_co 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 diff --git a/docs/sphinx_docs/_build/doctrees/types.doctree b/docs/sphinx_docs/_build/doctrees/types.doctree deleted file mode 100644 index dbb3cafcb75e073a47698417fe9af1fec108574e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16618 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 diff --git a/docs/sphinx_docs/_build/html/.buildinfo b/docs/sphinx_docs/_build/html/.buildinfo deleted file mode 100644 index 73c8c3e..0000000 --- a/docs/sphinx_docs/_build/html/.buildinfo +++ /dev/null @@ -1,4 +0,0 @@ -# Sphinx build info version 1 -# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: d581c6009ec2b560e43b1edcc2912d38 -tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/sphinx_docs/_build/html/_images/omg.svg b/docs/sphinx_docs/_build/html/_images/omg.svg deleted file mode 100644 index a3be69c..0000000 --- a/docs/sphinx_docs/_build/html/_images/omg.svg +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - -finite_state_machine - - -i - - -i - - -i->i - - -0 - - -j - -j - - -i->j - - -1 - - -h - - -h - - -h->i - - -0 - - -h->h - - -1 - - -a - -a - - -b - -b - - -a->b - - -0 - - -c - -c - - -a->c - - -1 - - -b->b - - -0 - - -d - -d - - -b->d - - -1 - - -c->b - - -0 - - -e - -e - - -c->e - - -1 - - -d->b - - -0 - - -f - -f - - -d->f - - -1 - - -e->b - - -0 - - -g - -g - - -e->g - - -1 - - -f->h - - -1 - - -f->b - - -0 - - -g->i - - -0 - - -g->g - - -1 - - -j->i - - -0 - - -j->h - - -1 - - - diff --git a/docs/sphinx_docs/_build/html/_modules/index.html b/docs/sphinx_docs/_build/html/_modules/index.html deleted file mode 100644 index 9ee35ef..0000000 --- a/docs/sphinx_docs/_build/html/_modules/index.html +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - Overview: module code — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - -

- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/joy.html b/docs/sphinx_docs/_build/html/_modules/joy/joy.html deleted file mode 100644 index f84d742..0000000 --- a/docs/sphinx_docs/_build/html/_modules/joy/joy.html +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - joy.joy — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Source code for joy.joy

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2014, 2015, 2017, 2018 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-This module implements an interpreter for a dialect of Joy that
-attempts to stay very close to the spirit of Joy but does not precisely
-match the behaviour of the original version(s) written in C.
-
-'''
-from builtins import input
-from traceback import print_exc
-from joy.parser import text_to_expression, ParseError, Symbol
-from joy.utils.stack import stack_to_string
-from joy.utils.errors import (
-    NotAListError,
-    NotAnIntError,
-    StackUnderflowError,
-    )
-
-
-
[docs]class UnknownSymbolError(KeyError): pass
- - -
[docs]def joy(stack, expression, dictionary, viewer=None): - ''' - Evaluate a Joy expression on a stack. - - This function iterates through a sequence of terms which are either - literals (strings, numbers, sequences of terms) or function symbols. - Literals are put onto the stack and functions are looked up in the - dictionary and executed. - - The viewer is a function that is called with the stack and expression - on every iteration, its return value is ignored. - - :param stack stack: The stack. - :param stack expression: The expression to evaluate. - :param dict dictionary: A ``dict`` mapping names to Joy functions. - :param function viewer: Optional viewer function. - :rtype: (stack, (), dictionary) - - ''' - while expression: - - if viewer: viewer(stack, expression) - - term, expression = expression - if isinstance(term, Symbol): - if term not in dictionary: - raise UnknownSymbolError(term) - func = dictionary[term] - stack, expression, dictionary = func(stack, expression, dictionary) - else: - stack = term, stack - - if viewer: viewer(stack, expression) - return stack, expression, dictionary
- - -
[docs]def run(text, stack, dictionary, viewer=None): - ''' - Return the stack resulting from running the Joy code text on the stack. - - :param str text: Joy code. - :param stack stack: The stack. - :param dict dictionary: A ``dict`` mapping names to Joy functions. - :param function viewer: Optional viewer function. - :rtype: (stack, (), dictionary) - - ''' - expression = text_to_expression(text) - return joy(stack, expression, dictionary, viewer)
- - -
[docs]def repl(stack=(), dictionary=None): - ''' - Read-Evaluate-Print Loop - - Accept input and run it on the stack, loop. - - :param stack stack: The stack. - :param dict dictionary: A ``dict`` mapping names to Joy functions. - :rtype: stack - - ''' - if dictionary is None: - dictionary = {} - try: - while True: - print() - print(stack_to_string(stack), '<-top') - print() - try: - text = input('joy? ') - except (EOFError, KeyboardInterrupt): - break - try: - stack, _, dictionary = run(text, stack, dictionary) - except: - print_exc() - except: - print_exc() - print() - return stack
- - -
[docs]def interp(stack=(), dictionary=None): - ''' - Simple REPL with no extra output, suitable for use in scripts. - ''' - if dictionary is None: - dictionary = {} - try: - while True: - try: - text = input() - except (EOFError, KeyboardInterrupt): - break - try: - stack, _, dictionary = run(text, stack, dictionary) - except UnknownSymbolError as sym: - print('Unknown:', sym) - except StackUnderflowError as e: - print(e) # 'Not enough values on stack.' - except NotAnIntError: - print('Not an integer.') - except NotAListError as e: - print(e) - except: - print_exc() - print(stack_to_string(stack)) - except: - print_exc() - return stack
-
- -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/library.html b/docs/sphinx_docs/_build/html/_modules/joy/library.html deleted file mode 100644 index 0b98def..0000000 --- a/docs/sphinx_docs/_build/html/_modules/joy/library.html +++ /dev/null @@ -1,1499 +0,0 @@ - - - - - - - - joy.library — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Source code for joy.library

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2014-2020 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>. 
-#
-'''
-This module contains the Joy function infrastructure and a library of
-functions.  Its main export is a Python function initialize() that
-returns a dictionary of Joy functions suitable for use with the joy()
-function.
-'''
-from pkg_resources import resource_stream
-from io import TextIOWrapper
-from inspect import getdoc, getmembers, isfunction
-from functools import wraps
-from itertools import count
-import operator, math
-
-from . import __name__ as _joy_package_name
-from .parser import text_to_expression, Symbol
-from .utils import generated_library as genlib
-from .utils.errors import (
-    NotAListError,
-    NotAnIntError,
-    StackUnderflowError,
-    )
-from .utils.stack import (
-    concat,
-    expression_to_string,
-    iter_stack,
-    list_to_stack,
-    pick,
-    )
-
-
-def default_defs(dictionary):
-    def_stream = TextIOWrapper(
-        resource_stream(_joy_package_name, 'defs.txt'),
-        encoding='UTF_8',
-        )
-    Def.load_definitions(def_stream, dictionary)
-
-
-HELP_TEMPLATE = '''\
-
-==== Help on %s ====
-
-%s
-
----- end ( %s )
-'''
-
-
-# This is the main dict we're building.
-_dictionary = {}
-
-
-
[docs]def inscribe(function, d=_dictionary): - '''A decorator to inscribe functions into the default dictionary.''' - d[function.name] = function - return function
- - -
[docs]def initialize(): - '''Return a dictionary of Joy functions for use with joy().''' - return _dictionary.copy()
- - -ALIASES = ( - ('add', ['+']), - ('and', ['&']), - ('bool', ['truthy']), - ('mul', ['*']), - ('floordiv', ['/floor', '//', '/', 'div']), - ('mod', ['%', 'rem', 'remainder', 'modulus']), - ('eq', ['=']), - ('ge', ['>=']), - ('getitem', ['pick', 'at']), - ('gt', ['>']), - ('le', ['<=']), - ('lshift', ['<<']), - ('lt', ['<']), - ('ne', ['<>', '!=']), - ('rshift', ['>>']), - ('sub', ['-']), - ('xor', ['^']), - ('succ', ['++']), - ('pred', ['--']), - ('rolldown', ['roll<']), - ('rollup', ['roll>']), - ('eh', ['?']), - ('id', [u'•']), - ) - - -
[docs]def add_aliases(D, A): - ''' - Given a dict and a iterable of (name, [alias, ...]) pairs, create - additional entries in the dict mapping each alias to the named function - if it's in the dict. Aliases for functions not in the dict are ignored. - ''' - for name, aliases in A: - try: - F = D[name] - except KeyError: - continue - for alias in aliases: - D[alias] = F
- - -
[docs]def FunctionWrapper(f): - '''Set name attribute.''' - if not f.__doc__: - raise ValueError('Function %s must have doc string.' % f.__name__) - f.name = f.__name__.rstrip('_') # Don't shadow builtins. - return f
- - -
[docs]def SimpleFunctionWrapper(f): - ''' - Wrap functions that take and return just a stack. - ''' - @FunctionWrapper - @wraps(f) - def inner(stack, expression, dictionary): - return f(stack), expression, dictionary - return inner
- - -
[docs]def BinaryMathWrapper(f): - ''' - Wrap functions that take two numbers and return a single result. - ''' - @FunctionWrapper - @wraps(f) - def inner(stack, expression, dictionary): - try: - (a, (b, stack)) = stack - except ValueError: - raise StackUnderflowError('Not enough values on stack.') - if ( not isinstance(a, int) - or not isinstance(b, int) - # bool is int in Python. - or isinstance(a, bool) - or isinstance(b, bool) - ): - raise NotAnIntError - result = f(b, a) - return (result, stack), expression, dictionary - return inner
- - -
[docs]def BinaryLogicWrapper(f): - ''' - Wrap functions that take two numbers and return a single result. - ''' - @FunctionWrapper - @wraps(f) - def inner(stack, expression, dictionary): - try: - (a, (b, stack)) = stack - except ValueError: - raise StackUnderflowError('Not enough values on stack.') -## if (not isinstance(a, bool) -## or not isinstance(b, bool) -## ): -## raise NotABoolError - result = f(b, a) - return (result, stack), expression, dictionary - return inner
- - -
[docs]def UnaryBuiltinWrapper(f): - ''' - Wrap functions that take one argument and return a single result. - ''' - @FunctionWrapper - @wraps(f) - def inner(stack, expression, dictionary): - (a, stack) = stack - result = f(a) - return (result, stack), expression, dictionary - return inner
- - -
[docs]class Def(object): - ''' - Definitions created by inscribe. - ''' - - def __init__(self, name, body): - self.name = name - self.body = body - self._body = tuple(iter_stack(body)) - self.__doc__ = expression_to_string(body) - self._compiled = None - - def __call__(self, stack, expression, dictionary): - if self._compiled: - return self._compiled(stack, expression, dictionary) # pylint: disable=E1102 - expression = list_to_stack(self._body, expression) - return stack, expression, dictionary - - @classmethod - def load_definitions(class_, stream, dictionary): - for line in stream: - if line.lstrip().startswith('#'): - continue - name, body = text_to_expression(line) - if name not in dictionary: - inscribe(class_(name, body), dictionary)
-## inscribe(class_(name, body), dictionary) - - -# -# Functions -# - - -
[docs]@inscribe -@FunctionWrapper -def inscribe_(stack, expression, dictionary): - ''' - Create a new Joy function definition in the Joy dictionary. A - definition is given as a quote with a name followed by a Joy - expression. for example: - - [sqr dup mul] inscribe - - ''' - (name, body), stack = stack - inscribe(Def(name, body), dictionary) - return stack, expression, dictionary
- - -# @inscribe -# @SimpleFunctionWrapper -# def infer_(stack): -# '''Attempt to infer the stack effect of a Joy expression.''' -# E, stack = stack -# effects = infer_expression(E) -# e = list_to_stack([(fi, (fo, ())) for fi, fo in effects]) -# return e, stack - - -
[docs]@inscribe -@SimpleFunctionWrapper -def getitem(stack): - ''' - :: - - getitem == drop first - - Expects an integer and a quote on the stack and returns the item at the - nth position in the quote counting from 0. - :: - - [a b c d] 0 getitem - ------------------------- - a - - ''' - n, (Q, stack) = stack - return pick(Q, n), stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def drop(stack): - ''' - :: - - drop == [rest] times - - Expects an integer and a quote on the stack and returns the quote with - n items removed off the top. - :: - - [a b c d] 2 drop - ---------------------- - [c d] - - ''' - n, (Q, stack) = stack - while n > 0: - try: - _, Q = Q - except ValueError: - raise IndexError - n -= 1 - return Q, stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def take(stack): - ''' - Expects an integer and a quote on the stack and returns the quote with - just the top n items in reverse order (because that's easier and you can - use reverse if needed.) - :: - - [a b c d] 2 take - ---------------------- - [b a] - - ''' - n, (Q, stack) = stack - x = () - while n > 0: - try: - item, Q = Q - except ValueError: - raise IndexError - x = item, x - n -= 1 - return x, stack
- - -
[docs]@inscribe -@FunctionWrapper -def gcd2(stack, expression, dictionary): - '''Compiled GCD function.''' - (v1, (v2, stack)) = stack - tos = True - while tos: - v3 = v2 % v1 - tos = v3 > 0 - (v1, (v2, stack)) = (v3, (v1, stack)) - return (v2, stack), expression, dictionary
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def choice(stack): - ''' - Use a Boolean value to select one of two items. - :: - - A B false choice - ---------------------- - A - - - A B true choice - --------------------- - B - - ''' - (if_, (then, (else_, stack))) = stack - assert isinstance(if_, bool), repr(if_) - return then if if_ else else_, stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def select(stack): - ''' - Use a Boolean value to select one of two items from a sequence. - :: - - [A B] false select - ------------------------ - A - - - [A B] true select - ----------------------- - B - - The sequence can contain more than two items but not fewer. - Currently Python semantics are used to evaluate the "truthiness" of the - Boolean value (so empty string, zero, etc. are counted as false, etc.) - ''' - (flag, (choices, stack)) = stack - (else_, (then, _)) = choices - return then if flag else else_, stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def max_(S): - '''Given a list find the maximum.''' - tos, stack = S - return max(iter_stack(tos)), stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def min_(S): - '''Given a list find the minimum.''' - tos, stack = S - return min(iter_stack(tos)), stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def sum_(S): - ''' - Given a quoted sequence of numbers return the sum. - :: - - sum == 0 swap [+] step - - ''' - tos, stack = S - return sum(iter_stack(tos)), stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def remove(S): - ''' - Expects an item on the stack and a quote under it and removes that item - from the the quote. The item is only removed once. If the list is - empty or the item isn't in the list then the list is unchanged. - :: - - [1 2 3 1] 1 remove - ------------------------ - [2 3 1] - - ''' - (item, (quote, stack)) = S - return _remove(item, quote), stack
- - -def _remove(item, quote): - try: head, tail = quote - except ValueError: return quote - return tail if head == item else (head, _remove(item, tail)) - - -
[docs]@inscribe -@SimpleFunctionWrapper -def unique(S): - '''Given a list remove duplicate items.''' - tos, stack = S - I = list(iter_stack(tos)) - return list_to_stack(sorted(set(I), key=I.index)), stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def sort_(S): - '''Given a list return it sorted.''' - tos, stack = S - return list_to_stack(sorted(iter_stack(tos))), stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def clear(stack): - '''Clear everything from the stack. - :: - - clear == stack [pop stack] loop - - ... clear - --------------- - - ''' - return ()
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def disenstacken(stack): - ''' - The disenstacken operator expects a list on top of the stack and makes that - the stack discarding the rest of the stack. - ''' - return stack[0]
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def reverse(S): - ''' - Reverse the list on the top of the stack. - :: - - reverse == [] swap shunt - ''' - (tos, stack) = S - res = () - for term in iter_stack(tos): - res = term, res - return res, stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def concat_(S): - ''' - Concatinate the two lists on the top of the stack. - :: - - [a b c] [d e f] concat - ---------------------------- - [a b c d e f] - - ''' - (tos, (second, stack)) = S - return concat(second, tos), stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def shunt(stack): - ''' - Like concat but reverses the top list into the second. - :: - - shunt == [swons] step == reverse swap concat - - [a b c] [d e f] shunt - --------------------------- - [f e d a b c] - - ''' - (tos, (second, stack)) = stack - while tos: - term, tos = tos - second = term, second - return second, stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def zip_(S): - ''' - Replace the two lists on the top of the stack with a list of the pairs - from each list. The smallest list sets the length of the result list. - ''' - (tos, (second, stack)) = S - accumulator = [ - (a, (b, ())) - for a, b in zip(iter_stack(tos), iter_stack(second)) - ] - return list_to_stack(accumulator), stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def succ(S): - '''Increment TOS.''' - (tos, stack) = S - return tos + 1, stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def pred(S): - '''Decrement TOS.''' - (tos, stack) = S - return tos - 1, stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def pm(stack): - ''' - Plus or minus - :: - - a b pm - ------------- - a+b a-b - - ''' - a, (b, stack) = stack - p, m, = b + a, b - a - return m, (p, stack)
- - -
[docs]def floor(n): - return int(math.floor(n))
- -floor.__doc__ = math.floor.__doc__ - - -
[docs]@inscribe -@SimpleFunctionWrapper -def divmod_(S): - ''' - divmod(x, y) -> (quotient, remainder) - - Return the tuple (x//y, x%y). Invariant: q * y + r == x. - ''' - y, (x, stack) = S - q, r = divmod(x, y) - return r, (q, stack)
- - -
[docs]def sqrt(a): - ''' - Return the square root of the number a. - Negative numbers return complex roots. - ''' - try: - r = math.sqrt(a) - except ValueError: - assert a < 0, repr(a) - r = math.sqrt(-a) * 1j - return r
- - -#def execute(S): -# (text, stack) = S -# if isinstance(text, str): -# return run(text, stack) -# return stack - - -
[docs]@inscribe -@SimpleFunctionWrapper -def id_(stack): - '''The identity function.''' - return stack
- - -
[docs]@inscribe -@SimpleFunctionWrapper -def void(stack): - '''True if the form on TOS is void otherwise False.''' - form, stack = stack - return _void(form), stack
- - -def _void(form): - return any(not _void(i) for i in iter_stack(form)) - - - -## transpose -## sign -## take - - -
[docs]@inscribe -@FunctionWrapper -def words(stack, expression, dictionary): - '''Print all the words in alphabetical order.''' - print(' '.join(sorted(dictionary))) - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def sharing(stack, expression, dictionary): - '''Print redistribution information.''' - print("You may convey verbatim copies of the Program's source code as" - ' you receive it, in any medium, provided that you conspicuously' - ' and appropriately publish on each copy an appropriate copyright' - ' notice; keep intact all notices stating that this License and' - ' any non-permissive terms added in accord with section 7 apply' - ' to the code; keep intact all notices of the absence of any' - ' warranty; and give all recipients a copy of this License along' - ' with the Program.' - ' You should have received a copy of the GNU General Public License' - ' along with Thun. If not see <http://www.gnu.org/licenses/>.') - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def warranty(stack, expression, dictionary): - '''Print warranty information.''' - print('THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY' - ' APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE' - ' COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM' - ' "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR' - ' IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES' - ' OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE' - ' ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS' - ' WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE' - ' COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.') - return stack, expression, dictionary
- - -# def simple_manual(stack): -# ''' -# Print words and help for each word. -# ''' -# for name, f in sorted(FUNCTIONS.items()): -# d = getdoc(f) -# boxline = '+%s+' % ('-' * (len(name) + 2)) -# print('\n'.join(( -# boxline, -# '| %s |' % (name,), -# boxline, -# d if d else ' ...', -# '', -# '--' * 40, -# '', -# ))) -# return stack - - -
[docs]@inscribe -@FunctionWrapper -def help_(S, expression, dictionary): - '''Accepts a quoted symbol on the top of the stack and prints its docs.''' - ((symbol, _), stack) = S - word = dictionary[symbol] - print(HELP_TEMPLATE % (symbol, getdoc(word), symbol)) - return stack, expression, dictionary
- - -# -# § Combinators -# - - -# Several combinators depend on other words in their definitions, -# we use symbols to prevent hard-coding these, so in theory, you -# could change the word in the dictionary to use different semantics. -S_choice = Symbol('choice') -S_first = Symbol('first') -S_genrec = Symbol('genrec') -S_getitem = Symbol('getitem') -S_i = Symbol('i') -S_ifte = Symbol('ifte') -S_infra = Symbol('infra') -S_loop = Symbol('loop') -S_pop = Symbol('pop') -S_primrec = Symbol('primrec') -S_step = Symbol('step') -S_swaack = Symbol('swaack') -S_times = Symbol('times') - - -
[docs]@inscribe -@FunctionWrapper -def i(stack, expression, dictionary): - ''' - The i combinator expects a quoted program on the stack and unpacks it - onto the pending expression for evaluation. - :: - - [Q] i - ----------- - Q - - ''' - try: - quote, stack = stack - except ValueError: - raise StackUnderflowError('Not enough values on stack.') - return stack, concat(quote, expression), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def x(stack, expression, dictionary): - ''' - :: - - x == dup i - - ... [Q] x = ... [Q] dup i - ... [Q] x = ... [Q] [Q] i - ... [Q] x = ... [Q] Q - - ''' - quote, _ = stack - return stack, concat(quote, expression), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def b(stack, expression, dictionary): - ''' - :: - - b == [i] dip i - - ... [P] [Q] b == ... [P] i [Q] i - ... [P] [Q] b == ... P Q - - ''' - q, (p, (stack)) = stack - return stack, concat(p, concat(q, expression)), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def ii(stack, expression, dictionary): - ''' - :: - - ... a [Q] ii - ------------------ - ... Q a Q - - ''' - quote, (a, stack) = stack - expression = concat(quote, (a, concat(quote, expression))) - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def dupdip(stack, expression, dictionary): - ''' - :: - - [F] dupdip == dup [F] dip - - ... a [F] dupdip - ... a dup [F] dip - ... a a [F] dip - ... a F a - - ''' - F, stack = stack - a = stack[0] - return stack, concat(F, (a, expression)), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def infra(stack, expression, dictionary): - ''' - Accept a quoted program and a list on the stack and run the program - with the list as its stack. Does not affect the rest of the stack. - :: - - ... [a b c] [Q] . infra - ----------------------------- - c b a . Q [...] swaack - - ''' - (quote, (aggregate, stack)) = stack - return aggregate, concat(quote, (stack, (S_swaack, expression))), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def genrec(stack, expression, dictionary): - ''' - General Recursion Combinator. - :: - - [if] [then] [rec1] [rec2] genrec - --------------------------------------------------------------------- - [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte - - From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun: - "The genrec combinator takes four program parameters in addition to - whatever data parameters it needs. Fourth from the top is an if-part, - followed by a then-part. If the if-part yields true, then the then-part - is executed and the combinator terminates. The other two parameters are - the rec1-part and the rec2-part. If the if-part yields false, the - rec1-part is executed. Following that the four program parameters and - the combinator are again pushed onto the stack bundled up in a quoted - form. Then the rec2-part is executed, where it will find the bundled - form. Typically it will then execute the bundled form, either with i or - with app2, or some other combinator." - - The way to design one of these is to fix your base case [then] and the - test [if], and then treat rec1 and rec2 as an else-part "sandwiching" - a quotation of the whole function. - - For example, given a (general recursive) function 'F': - :: - - F == [I] [T] [R1] [R2] genrec - - If the [I] if-part fails you must derive R1 and R2 from: - :: - - ... R1 [F] R2 - - Just set the stack arguments in front, and figure out what R1 and R2 - have to do to apply the quoted [F] in the proper way. In effect, the - genrec combinator turns into an ifte combinator with a quoted copy of - the original definition in the else-part: - :: - - F == [I] [T] [R1] [R2] genrec - == [I] [T] [R1 [F] R2] ifte - - Primitive recursive functions are those where R2 == i. - :: - - P == [I] [T] [R] tailrec - == [I] [T] [R [P] i] ifte - == [I] [T] [R P] ifte - - ''' - (rec2, (rec1, stack)) = stack - (then, (if_, _)) = stack - F = (if_, (then, (rec1, (rec2, (S_genrec, ()))))) - else_ = concat(rec1, (F, rec2)) - return (else_, stack), (S_ifte, expression), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def map_(S, expression, dictionary): - ''' - Run the quoted program on TOS on the items in the list under it, push a - new list with the results in place of the program and original list. - ''' - # (quote, (aggregate, stack)) = S - # results = list_to_stack([ - # joy((term, stack), quote, dictionary)[0][0] - # for term in iter_stack(aggregate) - # ]) - # return (results, stack), expression, dictionary - (quote, (aggregate, stack)) = S - if not aggregate: - return (aggregate, stack), expression, dictionary - batch = () - for term in iter_stack(aggregate): - s = term, stack - batch = (s, (quote, (S_infra, (S_first, batch)))) - stack = (batch, ((), stack)) - return stack, (S_infra, expression), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def primrec(stack, expression, dictionary): - ''' - From the "Overview of the language JOY": - - > The primrec combinator expects two quoted programs in addition to a - data parameter. For an integer data parameter it works like this: If - the data parameter is zero, then the first quotation has to produce - the value to be returned. If the data parameter is positive then the - second has to combine the data parameter with the result of applying - the function to its predecessor.:: - - 5 [1] [*] primrec - - > Then primrec tests whether the top element on the stack (initially - the 5) is equal to zero. If it is, it pops it off and executes one of - the quotations, the [1] which leaves 1 on the stack as the result. - Otherwise it pushes a decremented copy of the top element and - recurses. On the way back from the recursion it uses the other - quotation, [*], to multiply what is now a factorial on top of the - stack by the second element on the stack.:: - - n [Base] [Recur] primrec - - 0 [Base] [Recur] primrec - ------------------------------ - Base - - n [Base] [Recur] primrec - ------------------------------------------ n > 0 - n (n-1) [Base] [Recur] primrec Recur - - ''' - recur, (base, (n, stack)) = stack - if n <= 0: - expression = concat(base, expression) - else: - expression = S_primrec, concat(recur, expression) - stack = recur, (base, (n - 1, (n, stack))) - return stack, expression, dictionary
- - -#def cleave(S, expression, dictionary): -# ''' -# The cleave combinator expects two quotations, and below that an item X. -# It first executes [P], with X on top, and saves the top result element. -# Then it executes [Q], again with X, and saves the top result. -# Finally it restores the stack to what it was below X and pushes the two -# results P(X) and Q(X). -# ''' -# (Q, (P, (x, stack))) = S -# p = joy((x, stack), P, dictionary)[0][0] -# q = joy((x, stack), Q, dictionary)[0][0] -# return (q, (p, stack)), expression, dictionary - - -
[docs]@inscribe -@FunctionWrapper -def branch(stack, expression, dictionary): - ''' - Use a Boolean value to select one of two quoted programs to run. - - :: - - branch == roll< choice i - - :: - - False [F] [T] branch - -------------------------- - F - - True [F] [T] branch - ------------------------- - T - - ''' - (then, (else_, (flag, stack))) = stack - return stack, concat(then if flag else else_, expression), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def ifte(stack, expression, dictionary): - ''' - If-Then-Else Combinator - :: - - ... [if] [then] [else] ifte - --------------------------------------------------- - ... [[else] [then]] [...] [if] infra select i - - - - - ... [if] [then] [else] ifte - ------------------------------------------------------- - ... [else] [then] [...] [if] infra first choice i - - - Has the effect of grabbing a copy of the stack on which to run the - if-part using infra. - ''' - (else_, (then, (if_, stack))) = stack - expression = (S_infra, (S_first, (S_choice, (S_i, expression)))) - stack = (if_, (stack, (then, (else_, stack)))) - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def cond(stack, expression, dictionary): - ''' - This combinator works like a case statement. It expects a single quote - on the stack that must contain zero or more condition quotes and a - default quote. Each condition clause should contain a quoted predicate - followed by the function expression to run if that predicate returns - true. If no predicates return true the default function runs. - - It works by rewriting into a chain of nested `ifte` expressions, e.g.:: - - [[[B0] T0] [[B1] T1] [D]] cond - ----------------------------------------- - [B0] [T0] [[B1] [T1] [D] ifte] ifte - - ''' - conditions, stack = stack - if conditions: - expression = _cond(conditions, expression) - try: - # Attempt to preload the args to first ifte. - (P, (T, (E, expression))) = expression - except ValueError: - # If, for any reason, the argument to cond should happen to contain - # only the default clause then this optimization will fail. - pass - else: - stack = (E, (T, (P, stack))) - return stack, expression, dictionary
- - -def _cond(conditions, expression): - (clause, rest) = conditions - if not rest: # clause is [D] - return clause - P, T = clause - return (P, (T, (_cond(rest, ()), (S_ifte, expression)))) - - -
[docs]@inscribe -@FunctionWrapper -def dip(stack, expression, dictionary): - ''' - The dip combinator expects a quoted program on the stack and below it - some item, it hoists the item into the expression and runs the program - on the rest of the stack. - :: - - ... x [Q] dip - ------------------- - ... Q x - - ''' - try: - (quote, (x, stack)) = stack - except ValueError: - raise StackUnderflowError('Not enough values on stack.') - expression = (x, expression) - return stack, concat(quote, expression), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def dipd(S, expression, dictionary): - ''' - Like dip but expects two items. - :: - - ... y x [Q] dip - --------------------- - ... Q y x - - ''' - (quote, (x, (y, stack))) = S - expression = (y, (x, expression)) - return stack, concat(quote, expression), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def dipdd(S, expression, dictionary): - ''' - Like dip but expects three items. - :: - - ... z y x [Q] dip - ----------------------- - ... Q z y x - - ''' - (quote, (x, (y, (z, stack)))) = S - expression = (z, (y, (x, expression))) - return stack, concat(quote, expression), dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def app1(S, expression, dictionary): - ''' - Given a quoted program on TOS and anything as the second stack item run - the program and replace the two args with the first result of the - program. - :: - - ... x [Q] . app1 - ----------------------------------- - ... [x ...] [Q] . infra first - - ''' - (quote, (x, stack)) = S - stack = (quote, ((x, stack), stack)) - expression = (S_infra, (S_first, expression)) - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def app2(S, expression, dictionary): - '''Like app1 with two items. - :: - - ... y x [Q] . app2 - ----------------------------------- - ... [y ...] [Q] . infra first - [x ...] [Q] infra first - - ''' - (quote, (x, (y, stack))) = S - expression = (S_infra, (S_first, - ((x, stack), (quote, (S_infra, (S_first, - expression)))))) - stack = (quote, ((y, stack), stack)) - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def app3(S, expression, dictionary): - '''Like app1 with three items. - :: - - ... z y x [Q] . app3 - ----------------------------------- - ... [z ...] [Q] . infra first - [y ...] [Q] infra first - [x ...] [Q] infra first - - ''' - (quote, (x, (y, (z, stack)))) = S - expression = (S_infra, (S_first, - ((y, stack), (quote, (S_infra, (S_first, - ((x, stack), (quote, (S_infra, (S_first, - expression)))))))))) - stack = (quote, ((z, stack), stack)) - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def step(S, expression, dictionary): - ''' - Run a quoted program on each item in a sequence. - :: - - ... [] [Q] . step - ----------------------- - ... . - - - ... [a] [Q] . step - ------------------------ - ... a . Q - - - ... [a b c] [Q] . step - ---------------------------------------- - ... a . Q [b c] [Q] step - - The step combinator executes the quotation on each member of the list - on top of the stack. - ''' - (quote, (aggregate, stack)) = S - if not aggregate: - return stack, expression, dictionary - head, tail = aggregate - stack = quote, (head, stack) - if tail: - expression = tail, (quote, (S_step, expression)) - expression = S_i, expression - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def times(stack, expression, dictionary): - ''' - times == [-- dip] cons [swap] infra [0 >] swap while pop - :: - - ... n [Q] . times - --------------------- w/ n <= 0 - ... . - - - ... 1 [Q] . times - ----------------------- - ... . Q - - - ... n [Q] . times - ------------------------------------- w/ n > 1 - ... . Q (n - 1) [Q] times - - ''' - # times == [-- dip] cons [swap] infra [0 >] swap while pop - (quote, (n, stack)) = stack - if n <= 0: - return stack, expression, dictionary - n -= 1 - if n: - expression = n, (quote, (S_times, expression)) - expression = concat(quote, expression) - return stack, expression, dictionary
- - -# The current definition above works like this: - -# [P] [Q] while -# -------------------------------------- -# [P] nullary [Q [P] nullary] loop - -# while == [pop i not] [popop] [dudipd] tailrec - -#def while_(S, expression, dictionary): -# '''[if] [body] while''' -# (body, (if_, stack)) = S -# while joy(stack, if_, dictionary)[0][0]: -# stack = joy(stack, body, dictionary)[0] -# return stack, expression, dictionary - - -
[docs]@inscribe -@FunctionWrapper -def loop(stack, expression, dictionary): - ''' - Basic loop combinator. - :: - - ... True [Q] loop - ----------------------- - ... Q [Q] loop - - ... False [Q] loop - ------------------------ - ... - - ''' - try: - quote, stack = stack - except ValueError: - raise StackUnderflowError('Not enough values on stack.') - if not isinstance(quote, tuple): - raise NotAListError('Loop body not a list.') - try: - (flag, stack) = stack - except ValueError: - raise StackUnderflowError('Not enough values on stack.') - if flag: - expression = concat(quote, (quote, (S_loop, expression))) - return stack, expression, dictionary
- - -
[docs]@inscribe -@FunctionWrapper -def cmp_(stack, expression, dictionary): - ''' - cmp takes two values and three quoted programs on the stack and runs - one of the three depending on the results of comparing the two values: - :: - - a b [G] [E] [L] cmp - ------------------------- a > b - G - - a b [G] [E] [L] cmp - ------------------------- a = b - E - - a b [G] [E] [L] cmp - ------------------------- a < b - L - ''' - L, (E, (G, (b, (a, stack)))) = stack - expression = concat(G if a > b else L if a < b else E, expression) - return stack, expression, dictionary
- - -# FunctionWrapper(cleave), -# FunctionWrapper(while_), - - -for F in ( - - #divmod_ = pm = __(n2, n1), __(n4, n3) - - BinaryMathWrapper(operator.eq), - BinaryMathWrapper(operator.ge), - BinaryMathWrapper(operator.gt), - BinaryMathWrapper(operator.le), - BinaryMathWrapper(operator.lt), - BinaryMathWrapper(operator.ne), - - BinaryMathWrapper(operator.xor), - BinaryMathWrapper(operator.lshift), - BinaryMathWrapper(operator.rshift), - - BinaryLogicWrapper(operator.and_), - BinaryLogicWrapper(operator.or_), - - BinaryMathWrapper(operator.add), - BinaryMathWrapper(operator.floordiv), - BinaryMathWrapper(operator.mod), - BinaryMathWrapper(operator.mul), - BinaryMathWrapper(operator.pow), - BinaryMathWrapper(operator.sub), -## BinaryMathWrapper(operator.truediv), - - UnaryBuiltinWrapper(bool), - UnaryBuiltinWrapper(operator.not_), - - UnaryBuiltinWrapper(abs), - UnaryBuiltinWrapper(operator.neg), - UnaryBuiltinWrapper(sqrt), - - UnaryBuiltinWrapper(floor), - UnaryBuiltinWrapper(round), - ): - inscribe(F) -del F # Otherwise Sphinx autodoc will pick it up. - - -for name, primitive in getmembers(genlib, isfunction): - inscribe(SimpleFunctionWrapper(primitive)) - - -add_aliases(_dictionary, ALIASES) -
- -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/parser.html b/docs/sphinx_docs/_build/html/_modules/joy/parser.html deleted file mode 100644 index 13e63f1..0000000 --- a/docs/sphinx_docs/_build/html/_modules/joy/parser.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - joy.parser — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Source code for joy.parser

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2014, 2015, 2016, 2017 Simon Forman
-#
-#    This file is part of Thun.
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-This module exports a single function for converting text to a joy
-expression as well as a single Symbol class and a single Exception type.
-
-The Symbol string class is used by the interpreter to recognize literals
-by the fact that they are not Symbol objects.
-
-A crude grammar::
-
-    joy = term*
-    term = integer | '[' joy ']' | symbol
-
-A Joy expression is a sequence of zero or more terms.  A term is a
-literal value (integer or Joy expression) or a function symbol.
-Function symbols are sequences of non-blanks and cannot contain square
-brackets.   Terms must be separated by blanks, which can be omitted
-around square brackets.
-
-'''
-from re import Scanner
-from joy.utils.stack import list_to_stack
-from joy.utils.snippets import (
-    pat as SNIPPETS,
-    from_string,
-    Snippet,
-    )
-
-
-BRACKETS = r'\[|\]'
-BLANKS = r'\s+'
-WORDS = r'[^[\]\s]+'
-
-
-token_scanner = Scanner([
-    (SNIPPETS, lambda _, token: from_string(token)),
-    (BRACKETS, lambda _, token: token),
-    (BLANKS, None),
-    (WORDS, lambda _, token: token),
-    ])
-
-
-
[docs]class Symbol(str): - '''A string class that represents Joy function names.''' - __repr__ = str.__str__
- - -
[docs]def text_to_expression(text): - '''Convert a string to a Joy expression. - - When supplied with a string this function returns a Python datastructure - that represents the Joy datastructure described by the text expression. - Any unbalanced square brackets will raise a ParseError. - - :param str text: Text to convert. - :rtype: stack - :raises ParseError: if the parse fails. - ''' - return _parse(_tokenize(text))
- - -
[docs]class ParseError(ValueError): - '''Raised when there is a error while parsing text.'''
- - -def _tokenize(text): - '''Convert a text into a stream of tokens. - - Converts function names to Symbols. - - Raise ParseError (with some of the failing text) if the scan fails. - ''' - tokens, rest = token_scanner.scan(text) - if rest: - raise ParseError( - 'Scan failed at position %i, %r' - % (len(text) - len(rest), rest[:10]) - ) - return tokens - - -def _parse(tokens): - ''' - Return a stack/list expression of the tokens. - ''' - frame = [] - stack = [] - for tok in tokens: - if tok == '[': - stack.append(frame) - frame = [] - elif tok == ']': - v = frame - try: frame = stack.pop() - except IndexError: - raise ParseError('Extra closing bracket.') from None - frame.append(list_to_stack(v)) - elif tok == 'true': frame.append(True) - elif tok == 'false': frame.append(False) - elif isinstance(tok, Snippet): frame.append(tok) - else: - try: thing = int(tok) - except ValueError: thing = Symbol(tok) - frame.append(thing) - if stack: raise ParseError('Unclosed bracket.') - return list_to_stack(frame) -
- -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/utils/generated_library.html b/docs/sphinx_docs/_build/html/_modules/joy/utils/generated_library.html deleted file mode 100644 index 806e479..0000000 --- a/docs/sphinx_docs/_build/html/_modules/joy/utils/generated_library.html +++ /dev/null @@ -1,519 +0,0 @@ - - - - - - - - joy.utils.generated_library — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Source code for joy.utils.generated_library

-# GENERATED FILE. DO NOT EDIT.
-# The code that generated these functions is in the repo history
-# at the v0.4.0 tag.
-from .errors import NotAListError, StackUnderflowError
-
-
-def _Tree_add_Ee(stack):
-  """
-  ::
-
-    ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
-
-  """
-  (a1, (a2, (a3, ((a4, (a5, s1)), s2)))) = stack
-  return ((a2, (a3, s1)), s2)
-
-
-def _Tree_delete_R0(stack):
-  """
-  ::
-
-    ([a2 ...1] a1 -- [a2 ...1] a2 a1 a1)
-
-  """
-  (a1, ((a2, s1), s2)) = stack
-  return (a1, (a1, (a2, ((a2, s1), s2))))
-
-
-def _Tree_delete_clear_stuff(stack):
-  """
-  ::
-
-    (a3 a2 [a1 ...1] -- [...1])
-
-  """
-  ((a1, s1), (a2, (a3, s2))) = stack
-  return (s1, s2)
-
-
-def _Tree_get_E(stack):
-  """
-  ::
-
-    ([a3 a4 ...1] a2 a1 -- a4)
-
-  """
-  (a1, (a2, ((a3, (a4, s1)), s2))) = stack
-  return (a4, s2)
-
-
-
[docs]def ccons(stack): - """ - :: - - (a2 a1 [...1] -- [a2 a1 ...1]) - - """ - (s1, (a1, (a2, s2))) = stack - return ((a2, (a1, s1)), s2)
- - -
[docs]def cons(stack): - """ - :: - - (a1 [...0] -- [a1 ...0]) - - """ - try: s0, stack = stack - except ValueError: raise StackUnderflowError('Not enough values on stack.') - if not isinstance(s0, tuple): raise NotAListError('Not a list.') - try: a1, s23 = stack - except ValueError: raise StackUnderflowError('Not enough values on stack.') - return ((a1, s0), s23)
- - -
[docs]def dup(stack): - """ - :: - - (a1 -- a1 a1) - - """ - (a1, s23) = stack - return (a1, (a1, s23))
- - -
[docs]def dupd(stack): - """ - :: - - (a2 a1 -- a2 a2 a1) - - """ - (a1, (a2, s23)) = stack - return (a1, (a2, (a2, s23)))
- - -
[docs]def dupdd(stack): - """ - :: - - (a3 a2 a1 -- a3 a3 a2 a1) - - """ - (a1, (a2, (a3, s23))) = stack - return (a1, (a2, (a3, (a3, s23))))
- - -
[docs]def first(stack): - """ - :: - - ([a1 ...1] -- a1) - - """ - ((a1, s1), s23) = stack - return (a1, s23)
- - -
[docs]def first_two(stack): - """ - :: - - ([a1 a2 ...1] -- a1 a2) - - """ - ((a1, (a2, s1)), s2) = stack - return (a2, (a1, s2))
- - -
[docs]def fourth(stack): - """ - :: - - ([a1 a2 a3 a4 ...1] -- a4) - - """ - ((a1, (a2, (a3, (a4, s1)))), s2) = stack - return (a4, s2)
- - -
[docs]def over(stack): - """ - :: - - (a2 a1 -- a2 a1 a2) - - """ - (a1, (a2, s23)) = stack - return (a2, (a1, (a2, s23)))
- - -
[docs]def pop(stack): - """ - :: - - (a1 --) - - """ - try: - (a1, s23) = stack - except ValueError: - raise StackUnderflowError('Cannot pop empty stack.') - return s23
- - -
[docs]def popd(stack): - """ - :: - - (a2 a1 -- a1) - - """ - (a1, (a2, s23)) = stack - return (a1, s23)
- - -
[docs]def popdd(stack): - """ - :: - - (a3 a2 a1 -- a2 a1) - - """ - (a1, (a2, (a3, s23))) = stack - return (a1, (a2, s23))
- - -
[docs]def popop(stack): - """ - :: - - (a2 a1 --) - - """ - (a1, (a2, s23)) = stack - return s23
- - -
[docs]def popopd(stack): - """ - :: - - (a3 a2 a1 -- a1) - - """ - (a1, (a2, (a3, s23))) = stack - return (a1, s23)
- - -
[docs]def popopdd(stack): - """ - :: - - (a4 a3 a2 a1 -- a2 a1) - - """ - (a1, (a2, (a3, (a4, s23)))) = stack - return (a1, (a2, s23))
- - -
[docs]def rest(stack): - """ - :: - - ([a1 ...0] -- [...0]) - - """ - try: - s0, stack = stack - except ValueError: - raise StackUnderflowError - if not isinstance(s0, tuple): - raise NotAListError('Not a list.') - try: - _, s1 = s0 - except ValueError: - raise StackUnderflowError('Cannot take rest of empty list.') - return (s1, stack)
- - -
[docs]def rolldown(stack): - """ - :: - - (a1 a2 a3 -- a2 a3 a1) - - """ - (a3, (a2, (a1, s23))) = stack - return (a1, (a3, (a2, s23)))
- - -
[docs]def rollup(stack): - """ - :: - - (a1 a2 a3 -- a3 a1 a2) - - """ - (a3, (a2, (a1, s23))) = stack - return (a2, (a1, (a3, s23)))
- - -
[docs]def rrest(stack): - """ - :: - - ([a1 a2 ...1] -- [...1]) - - """ - ((a1, (a2, s1)), s2) = stack - return (s1, s2)
- - -
[docs]def second(stack): - """ - :: - - ([a1 a2 ...1] -- a2) - - """ - ((a1, (a2, s1)), s2) = stack - return (a2, s2)
- - -
[docs]def stack(stack): - """ - :: - - (... -- ... [...]) - - """ - s0 = stack - return (s0, s0)
- - -
[docs]def stuncons(stack): - """ - :: - - (... a1 -- ... a1 a1 [...]) - - """ - (a1, s1) = stack - return (s1, (a1, (a1, s1)))
- - -
[docs]def stununcons(stack): - """ - :: - - (... a2 a1 -- ... a2 a1 a1 a2 [...]) - - """ - (a1, (a2, s1)) = stack - return (s1, (a2, (a1, (a1, (a2, s1)))))
- - -
[docs]def swaack(stack): - """ - :: - - ([...1] -- [...0]) - - """ - try: - (s1, s0) = stack - except ValueError: - raise StackUnderflowError('Not enough values on stack.') - if not isinstance(s1, tuple): - raise NotAListError('Not a list.') - return (s0, s1)
- - -
[docs]def swap(stack): - """ - :: - - (a1 a2 -- a2 a1) - - """ - try: - (a2, (a1, s23)) = stack - except ValueError: - raise StackUnderflowError('Not enough values on stack.') - return (a1, (a2, s23))
- - -
[docs]def swons(stack): - """ - :: - - ([...1] a1 -- [a1 ...1]) - - """ - (a1, (s1, s2)) = stack - return ((a1, s1), s2)
- - -
[docs]def third(stack): - """ - :: - - ([a1 a2 a3 ...1] -- a3) - - """ - ((a1, (a2, (a3, s1))), s2) = stack - return (a3, s2)
- - -
[docs]def tuck(stack): - """ - :: - - (a2 a1 -- a1 a2 a1) - - """ - (a1, (a2, s23)) = stack - return (a1, (a2, (a1, s23)))
- - -
[docs]def uncons(stack): - """ - :: - - ([a1 ...0] -- a1 [...0]) - - """ - ((a1, s0), s23) = stack - return (s0, (a1, s23))
- - -
[docs]def unit(stack): - """ - :: - - (a1 -- [a1 ]) - - """ - (a1, s23) = stack - return ((a1, ()), s23)
- - -
[docs]def unswons(stack): - """ - :: - - ([a1 ...1] -- [...1] a1) - - """ - ((a1, s1), s2) = stack - return (a1, (s1, s2))
- -
- -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/utils/pretty_print.html b/docs/sphinx_docs/_build/html/_modules/joy/utils/pretty_print.html deleted file mode 100644 index 0a20441..0000000 --- a/docs/sphinx_docs/_build/html/_modules/joy/utils/pretty_print.html +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - joy.utils.pretty_print — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Source code for joy.utils.pretty_print

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2016 Simon Forman
-#
-#    This file is part of Thun.
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-Pretty printing support, e.g.::
-
-    Joy? [23 18 * 99 +] trace
-           • 23 18 mul 99 add
-        23 • 18 mul 99 add
-     23 18 • mul 99 add
-       414 • 99 add
-    414 99 • add
-       513 • 
-
-    513 <-top
-
-    joy? 
-
-On each line the stack is printed with the top to the left, then a
-bullet symbol, •, to represent the current locus of processing, then
-the pending expression to the right.
-'''
-# (Kinda clunky and hacky.  This should be swapped out in favor of much
-# smarter stuff.)
-from traceback import print_exc
-from .stack import expression_to_string, stack_to_string
-from ..joy import joy
-from ..library import FunctionWrapper
-
-
-
[docs]@FunctionWrapper -def trace(stack, expression, dictionary): - '''Evaluate a Joy expression on a stack and print a trace. - - This function is just like the `i` combinator but it also prints a - trace of the evaluation - - :param stack stack: The stack. - :param stack expression: The expression to evaluate. - :param dict dictionary: A ``dict`` mapping names to Joy functions. - :rtype: (stack, (), dictionary) - - ''' - tp = TracePrinter() - quote, stack = stack - try: - s, _, d = joy(stack, quote, dictionary, tp.viewer) - except: - tp.print_() - print('-' * 73) - raise - else: - tp.print_() - return s, expression, d
- - -
[docs]class TracePrinter(object): - ''' - This is what does the formatting. You instantiate it and pass the ``viewer()`` - method to the :py:func:`joy.joy.joy` function, then print it to see the - trace. - ''' - - def __init__(self): - self.history = [] - -
[docs] def viewer(self, stack, expression): - ''' - Record the current stack and expression in the TracePrinter's history. - Pass this method as the ``viewer`` argument to the :py:func:`joy.joy.joy` function. - - :param stack quote: A stack. - :param stack expression: A stack. - ''' - self.history.append((stack, expression))
- - def __str__(self): - return '\n'.join(self.go()) - -
[docs] def go(self): - ''' - Return a list of strings, one for each entry in the history, prefixed - with enough spaces to align all the interpreter dots. - - This method is called internally by the ``__str__()`` method. - - :rtype: list(str) - ''' - max_stack_length = 0 - lines = [] - for stack, expression in self.history: - stack = stack_to_string(stack) - expression = expression_to_string(expression) - n = len(stack) - if n > max_stack_length: - max_stack_length = n - lines.append((n, '%s%s' % (stack, expression))) - for i in range(len(lines)): # Prefix spaces to line up '•'s. - length, line = lines[i] - lines[i] = (' ' * (max_stack_length - length) + line) - return lines
- - def print_(self): - try: - print(self) - except: - print_exc() - print('Exception while printing viewer.')
-
- -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_modules/joy/utils/stack.html b/docs/sphinx_docs/_build/html/_modules/joy/utils/stack.html deleted file mode 100644 index d0cba1d..0000000 --- a/docs/sphinx_docs/_build/html/_modules/joy/utils/stack.html +++ /dev/null @@ -1,377 +0,0 @@ - - - - - - - - joy.utils.stack — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Source code for joy.utils.stack

-# -*- coding: utf-8 -*-
-#
-#    Copyright © 2014, 2015, 2017 Simon Forman
-#
-#    This file is part of Thun
-#
-#    Thun is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    Thun is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with Thun.  If not see <http://www.gnu.org/licenses/>.
-#
-'''
-When talking about Joy we use the terms "stack", "quote", "sequence",
-"list", and others to mean the same thing: a simple linear datatype that
-permits certain operations such as iterating and pushing and popping
-values from (at least) one end.
-
-    In describing Joy I have used the term quotation to describe all of the
-    above, because I needed a word to describe the arguments to combinators
-    which fulfill the same role in Joy as lambda abstractions (with
-    variables) fulfill in the more familiar functional languages. I use the
-    term list for those quotations whose members are what I call literals:
-    numbers, characters, truth values, sets, strings and other quotations.
-    All these I call literals because their occurrence in code results in
-    them being pushed onto the stack. But I also call [London Paris] a list.
-    So, [dup \*] is a quotation but not a list.
-
-`"A Conversation with Manfred von Thun" w/ Stevan Apter <http://archive.vector.org.uk/art10000350>`_ 
-
-There is no "Stack" Python class, instead we use the  `cons list`_, a 
-venerable two-tuple recursive sequence datastructure, where the
-empty tuple ``()`` is the empty stack and ``(head, rest)`` gives the
-recursive form of a stack with one or more items on it::
-
-    stack := () | (item, stack)
-
-Putting some numbers onto a stack::
-
-    ()
-    (1, ())
-    (2, (1, ()))
-    (3, (2, (1, ())))
-    ...
-
-Python has very nice "tuple packing and unpacking" in its syntax which
-means we can directly "unpack" the expected arguments to a Joy function.
-
-For example::
-
-    def dup((head, tail)):
-        return head, (head, tail)
-
-We replace the argument "stack" by the expected structure of the stack,
-in this case "(head, tail)", and Python takes care of unpacking the
-incoming tuple and assigning values to the names.  (Note that Python
-syntax doesn't require parentheses around tuples used in expressions
-where they would be redundant.)
-
-Unfortunately, the Sphinx documentation generator, which is used to generate this
-web page, doesn't handle tuples in the function parameters.  And in Python 3, this
-syntax was removed entirely.  Instead you would have to write::
-
-    def dup(stack):
-        head, tail = stack
-        return head, (head, tail)
-
-
-We have two very simple functions, one to build up a stack from a Python
-list and another to iterate through a stack and yield its items
-one-by-one in order.  There are also two functions to generate string representations
-of stacks.  They only differ in that one prints the terms in stack from left-to-right while the other prints from right-to-left.  In both functions *internal stacks* are
-printed left-to-right.  These functions are written to support :doc:`../pretty`.
-
-.. _cons list: https://en.wikipedia.org/wiki/Cons#Lists
-
-'''
-from .errors import NotAListError
-from .snippets import Snippet, to_string as snip_to_string
-
-
-
[docs]def list_to_stack(el, stack=()): - '''Convert a Python list (or other sequence) to a Joy stack:: - - [1, 2, 3] -> (1, (2, (3, ()))) - - :param list el: A Python list or other sequence (iterators and generators - won't work because ``reverse()`` is called on ``el``.) - :param stack stack: A stack, optional, defaults to the empty stack. This - allows for concatinating Python lists (or other sequence objects) - onto an existing Joy stack. - :rtype: stack - - ''' - for item in reversed(el): - stack = item, stack - return stack
- - -
[docs]def iter_stack(stack): - '''Iterate through the items on the stack. - - :param stack stack: A stack. - :rtype: iterator - ''' - while stack: - item, stack = stack - yield item
- - -
[docs]def stack_to_string(stack): - ''' - Return a "pretty print" string for a stack. - - The items are written right-to-left:: - - (top, (second, ...)) -> '... second top' - - :param stack stack: A stack. - :rtype: str - ''' - f = lambda stack: reversed(list(iter_stack(stack))) - return _to_string(stack, f)
- - -
[docs]def expression_to_string(expression): - ''' - Return a "pretty print" string for a expression. - - The items are written left-to-right:: - - (top, (second, ...)) -> 'top second ...' - - :param stack expression: A stack. - :rtype: str - ''' - return _to_string(expression, iter_stack)
- - -JOY_BOOL_LITERALS = 'false', 'true' - - -def _joy_repr(thing): - if isinstance(thing, bool): return JOY_BOOL_LITERALS[thing] - if isinstance(thing, Snippet): return snip_to_string(thing) - return repr(thing) - - -def _to_string(stack, f): - if not isinstance(stack, tuple): return _joy_repr(stack) - if not stack: return '' # shortcut - if isinstance(stack, Snippet): return snip_to_string(stack) - return ' '.join(map(_s, f(stack))) - - -_s = lambda s: ( - '[%s]' % expression_to_string(s) - if isinstance(s, tuple) - and not isinstance(s, Snippet) - # Is it worth making a non-tuple class for Snippet? - # Doing this check on each tuple seems a bit much. - else _joy_repr(s) - ) - - -
[docs]def concat(quote, expression): - '''Concatinate quote onto expression. - - In joy [1 2] [3 4] would become [1 2 3 4]. - - :param stack quote: A stack. - :param stack expression: A stack. - :rtype: stack - ''' - # This is the fastest implementation, but will trigger - # RuntimeError: maximum recursion depth exceeded - # on quotes longer than sys.getrecursionlimit(). - # :raises RuntimeError: if quote is larger than sys.getrecursionlimit(). - -## return (quote[0], concat(quote[1], expression)) if quote else expression - - # Original implementation. - -## return list_to_stack(list(iter_stack(quote)), expression) - - # In-lining is slightly faster (and won't break the - # recursion limit on long quotes.) - - if not isinstance(quote, tuple): - raise NotAListError('Not a list.') - temp = [] - while quote: - item, quote = quote - temp.append(item) - for item in reversed(temp): - expression = item, expression - return expression
- - - -
[docs]def dnd(stack, from_index, to_index): - ''' - Given a stack and two indices return a rearranged stack. - First remove the item at from_index and then insert it at to_index, - the second index is relative to the stack after removal of the item - at from_index. - - This function reuses all of the items and as much of the stack as it - can. It's meant to be used by remote clients to support drag-n-drop - rearranging of the stack from e.g. the StackListbox. - ''' - assert 0 <= from_index - assert 0 <= to_index - if from_index == to_index: - return stack - head, n = [], from_index - while True: - item, stack = stack - n -= 1 - if n < 0: - break - head.append(item) - assert len(head) == from_index - # now we have two cases: - diff = from_index - to_index - if diff < 0: - # from < to - # so the destination index is still in the stack - while diff: - h, stack = stack - head.append(h) - diff += 1 - else: - # from > to - # so the destination is in the head list - while diff: - stack = head.pop(), stack - diff -= 1 - stack = item, stack - while head: - stack = head.pop(), stack - return stack
- - -
[docs]def pick(stack, n): - ''' - Return the nth item on the stack. - - :param stack stack: A stack. - :param int n: An index into the stack. - :raises ValueError: if ``n`` is less than zero. - :raises IndexError: if ``n`` is equal to or greater than the length of ``stack``. - :rtype: whatever - ''' - if n < 0: - raise ValueError - while True: - try: - item, stack = stack - except ValueError: - raise IndexError - n -= 1 - if n < 0: - break - return item
-
- -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_sources/index.rst.txt b/docs/sphinx_docs/_build/html/_sources/index.rst.txt deleted file mode 100644 index 7cbd506..0000000 --- a/docs/sphinx_docs/_build/html/_sources/index.rst.txt +++ /dev/null @@ -1,140 +0,0 @@ -.. Thun documentation master file, created by - sphinx-quickstart on Sun Apr 22 15:19:55 2018. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Thun |release| Documentation -============================ - -Thun is dialect of Joy written in Python. - -`Joy`_ is a programming language created by Manfred von Thun that is easy to -use and understand and has many other nice properties. This Python -package implements an interpreter for a dialect of Joy that attempts to -stay very close to the spirit of Joy but does not precisely match the -behaviour of the original version(s) written in C. The main difference -between Thun and the originals, other than being written in Python, is -that it works by the "Continuation-Passing Style". - -Joy is: - -* `Purely Functional `__ -* `Stack-based `__ -* `Concatinative`_ ( See also `concatenative.org `__) -* :doc:`Categorical ` - -I hope that this package is useful in the sense that it provides an -additional joy interpreter (the binary in the archive from La Trobe seems -to run just fine on my modern Linux machine!) But I also hope that you -can read and understand the Python code and play with the implementation -itself. - -.. _Joy: https://en.wikipedia.org/wiki/Joy_(programming_language) - -.. _Concatinative: https://en.wikipedia.org/wiki/Concatenative_programming_language - - -Example Code --------------------------------------------------- - -Here is an example of Joy code:: - - [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte - -It might seem unreadable but with a little familiarity it becomes just as -legible as any other notation. Some layout helps:: - - [ [[abs] ii <=] - [ - [<>] [pop !-] || - ] && - ] - [[ !-] [[++]] [[--]] ifte dip] - [[pop !-] [--] [++] ifte ] - ifte - -This function accepts two integers on the stack and increments or -decrements one of them such that the new pair of numbers is the next -coordinate pair in a square spiral (like the kind used to construct an -`Ulam Spiral`_). For more information see :doc:`notebooks/Square_Spiral` - -.. _Ulam Spiral: https://en.wikipedia.org/wiki/Ulam_spiral - - -Quick Start --------------------------------------------------- - -Install from `PyPI`_ in the usual way:: - - $ pip install Thun - -To start the REPL:: - - $ python -m joy - -Continue with :doc:`the introduction `. - -.. _PyPI: https://pypi.org/project/Thun/ - - -Project Hosted on `OSDN`_ -------------------------- - -* `Source Repository`_ (`mirror`_) -* `Bug tracker`_ (`old tracker`_) -* `Forums`_ -* `Mailing list`_ - -.. _Bug tracker: https://todo.sr.ht/~sforman/thun-der -.. _old tracker: https://osdn.net/projects/joypy/ticket/ -.. _Forums: https://osdn.net/projects/joypy/forums/ -.. _Mailing list: https://osdn.net/projects/joypy/lists/ -.. _OSDN: https://osdn.net/projects/joypy/ -.. _Source Repository: https://osdn.net/projects/joypy/scm/git/Thun/ -.. _mirror: https://github.com/calroc/Thun - - -Information on the Joy language -------------------------------- - -See `the Wikipedia article`_ and `Kevin Albrecht's mirror of Manfred von Thun's original website for the Joy Programming Language`_ for more information on the Joy language. - -The best source (no pun intended) for learning about Joy is the -information made available at the website of La Trobe University (see the -mirror link above) which contains source code for the -original C interpreter, Joy language source code for various functions, -and a great deal of fascinating material mostly written by Von Thun on -Joy and its deeper facets as well as how to program in it and several -interesting aspects. It's quite a treasure trove. - -.. _the Wikipedia article: https://en.wikipedia.org/wiki/Joy_(programming_language) - -.. _Kevin Albrecht's mirror of Manfred von Thun's original website for the Joy Programming Language: http://www.kevinalbrecht.com/code/joy-mirror/index.html - - -Documentation on Thun Dialect ------------------------------ - -The following is specific information for this dialect of Joy. - -.. toctree:: - :maxdepth: 2 - - notebooks/Intro - joy - stack - parser - pretty - library - lib - types - notebooks/index - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/sphinx_docs/_build/html/_sources/joy.rst.txt b/docs/sphinx_docs/_build/html/_sources/joy.rst.txt deleted file mode 100644 index ad7618a..0000000 --- a/docs/sphinx_docs/_build/html/_sources/joy.rst.txt +++ /dev/null @@ -1,13 +0,0 @@ - -Joy Interpreter -=============== - - -``joy.joy`` ---------------- - - -.. automodule:: joy.joy - :members: - - diff --git a/docs/sphinx_docs/_build/html/_sources/lib.rst.txt b/docs/sphinx_docs/_build/html/_sources/lib.rst.txt deleted file mode 100644 index e341820..0000000 --- a/docs/sphinx_docs/_build/html/_sources/lib.rst.txt +++ /dev/null @@ -1,1761 +0,0 @@ - -Functions Grouped by, er, Function with Examples ------------------------------------------------- - -.. code:: python - - from notebook_preamble import J, V - -Stack Chatter -============= - -This is what I like to call the functions that just rearrange things on -the stack. (One thing I want to mention is that during a hypothetical -compilation phase these "stack chatter" words effectively disappear -because we can map the logical stack locations to registers that remain -static for the duration of the computation. This remains to be done but -it's "off the shelf" technology.) - -``clear`` -~~~~~~~~~ - -.. code:: python - - J('1 2 3 clear') - - -.. parsed-literal:: - - (nothing) - - -``dup`` ``dupd`` -~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 dup') - - -.. parsed-literal:: - - 1 2 3 3 - - -.. code:: python - - J('1 2 3 dupd') - - -.. parsed-literal:: - - 1 2 2 3 - - -``enstacken`` ``disenstacken`` ``stack`` ``unstack`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -(I may have these paired up wrong. I.e. ``disenstacken`` should be -``unstack`` and vice versa.) - -.. code:: python - - J('1 2 3 enstacken') # Replace the stack with a quote of itself. - - -.. parsed-literal:: - - [3 2 1] - - -.. code:: python - - J('4 5 6 [3 2 1] disenstacken') # Unpack a list onto the stack. - - -.. parsed-literal:: - - 4 5 6 3 2 1 - - -.. code:: python - - J('1 2 3 stack') # Get the stack on the stack. - - -.. parsed-literal:: - - 1 2 3 [3 2 1] - - -.. code:: python - - 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. - - -.. parsed-literal:: - - 6 5 4 - - -``pop`` ``popd`` ``popop`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 pop') - - -.. parsed-literal:: - - 1 2 - - -.. code:: python - - J('1 2 3 popd') - - -.. parsed-literal:: - - 1 3 - - -.. code:: python - - J('1 2 3 popop') - - -.. parsed-literal:: - - 1 - - -``roll<`` ``rolldown`` ``roll>`` ``rollup`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The "down" and "up" refer to the movement of two of the top three items -(displacing the third.) - -.. code:: python - - J('1 2 3 roll<') - - -.. parsed-literal:: - - 2 3 1 - - -.. code:: python - - J('1 2 3 roll>') - - -.. parsed-literal:: - - 3 1 2 - - -``swap`` -~~~~~~~~ - -.. code:: python - - J('1 2 3 swap') - - -.. parsed-literal:: - - 1 3 2 - - -``tuck`` ``over`` -~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 tuck') - - -.. parsed-literal:: - - 1 3 2 3 - - -.. code:: python - - J('1 2 3 over') - - -.. parsed-literal:: - - 1 2 3 2 - - -``unit`` ``quoted`` ``unquoted`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 unit') - - -.. parsed-literal:: - - 1 2 [3] - - -.. code:: python - - J('1 2 3 quoted') - - -.. parsed-literal:: - - 1 [2] 3 - - -.. code:: python - - J('1 [2] 3 unquoted') - - -.. parsed-literal:: - - 1 2 3 - - -.. code:: python - - V('1 [dup] 3 unquoted') # Unquoting evaluates. Be aware. - - -.. parsed-literal:: - - . 1 [dup] 3 unquoted - 1 . [dup] 3 unquoted - 1 [dup] . 3 unquoted - 1 [dup] 3 . unquoted - 1 [dup] 3 . [i] dip - 1 [dup] 3 [i] . dip - 1 [dup] . i 3 - 1 . dup 3 - 1 1 . 3 - 1 1 3 . - - -List words -========== - -``concat`` ``swoncat`` ``shunt`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3] [4 5 6] concat') - - -.. parsed-literal:: - - [1 2 3 4 5 6] - - -.. code:: python - - J('[1 2 3] [4 5 6] swoncat') - - -.. parsed-literal:: - - [4 5 6 1 2 3] - - -.. code:: python - - J('[1 2 3] [4 5 6] shunt') - - -.. parsed-literal:: - - [6 5 4 1 2 3] - - -``cons`` ``swons`` ``uncons`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 [2 3] cons') - - -.. parsed-literal:: - - [1 2 3] - - -.. code:: python - - J('[2 3] 1 swons') - - -.. parsed-literal:: - - [1 2 3] - - -.. code:: python - - J('[1 2 3] uncons') - - -.. parsed-literal:: - - 1 [2 3] - - -``first`` ``second`` ``third`` ``rest`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 4] first') - - -.. parsed-literal:: - - 1 - - -.. code:: python - - J('[1 2 3 4] second') - - -.. parsed-literal:: - - 2 - - -.. code:: python - - J('[1 2 3 4] third') - - -.. parsed-literal:: - - 3 - - -.. code:: python - - J('[1 2 3 4] rest') - - -.. parsed-literal:: - - [2 3 4] - - -``flatten`` -~~~~~~~~~~~ - -.. code:: python - - J('[[1] [2 [3] 4] [5 6]] flatten') - - -.. parsed-literal:: - - [1 2 [3] 4 5 6] - - -``getitem`` ``at`` ``of`` ``drop`` ``take`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``at`` and ``getitem`` are the same function. ``of == swap at`` - -.. code:: python - - J('[10 11 12 13 14] 2 getitem') - - -.. parsed-literal:: - - 12 - - -.. code:: python - - J('[1 2 3 4] 0 at') - - -.. parsed-literal:: - - 1 - - -.. code:: python - - J('2 [1 2 3 4] of') - - -.. parsed-literal:: - - 3 - - -.. code:: python - - J('[1 2 3 4] 2 drop') - - -.. parsed-literal:: - - [3 4] - - -.. code:: python - - J('[1 2 3 4] 2 take') # reverses the order - - -.. parsed-literal:: - - [2 1] - - -``reverse`` could be defines as ``reverse == dup size take`` - -``remove`` -~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 1 4] 1 remove') - - -.. parsed-literal:: - - [2 3 1 4] - - -``reverse`` -~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 4] reverse') - - -.. parsed-literal:: - - [4 3 2 1] - - -``size`` -~~~~~~~~ - -.. code:: python - - J('[1 1 1 1] size') - - -.. parsed-literal:: - - 4 - - -``swaack`` -~~~~~~~~~~ - -"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. Neither of the lists/stacks change their order. - -.. code:: python - - J('1 2 3 [4 5 6] swaack') - - -.. parsed-literal:: - - 6 5 4 [3 2 1] - - -``choice`` ``select`` -~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 1 choice') - - -.. parsed-literal:: - - 9 - - -.. code:: python - - J('23 9 0 choice') - - -.. parsed-literal:: - - 23 - - -.. code:: python - - J('[23 9 7] 1 select') # select is basically getitem, should retire it? - - -.. parsed-literal:: - - 9 - - -.. code:: python - - J('[23 9 7] 0 select') - - -.. parsed-literal:: - - 23 - - -``zip`` -~~~~~~~ - -.. code:: python - - J('[1 2 3] [6 5 4] zip') - - -.. parsed-literal:: - - [[6 1] [5 2] [4 3]] - - -.. code:: python - - J('[1 2 3] [6 5 4] zip [sum] map') - - -.. parsed-literal:: - - [7 7 7] - - -Math words -========== - -``+`` ``add`` -~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 +') - - -.. parsed-literal:: - - 32 - - -``-`` ``sub`` -~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 -') - - -.. parsed-literal:: - - 14 - - -``*`` ``mul`` -~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 *') - - -.. parsed-literal:: - - 207 - - -``/`` ``div`` ``floordiv`` ``truediv`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 /') - - -.. parsed-literal:: - - 2.5555555555555554 - - -.. code:: python - - J('23 -9 truediv') - - -.. parsed-literal:: - - -2.5555555555555554 - - -.. code:: python - - J('23 9 div') - - -.. parsed-literal:: - - 2 - - -.. code:: python - - J('23 9 floordiv') - - -.. parsed-literal:: - - 2 - - -.. code:: python - - J('23 -9 div') - - -.. parsed-literal:: - - -3 - - -.. code:: python - - J('23 -9 floordiv') - - -.. parsed-literal:: - - -3 - - -``%`` ``mod`` ``modulus`` ``rem`` ``remainder`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 %') - - -.. parsed-literal:: - - 5 - - -``neg`` -~~~~~~~ - -.. code:: python - - J('23 neg -5 neg') - - -.. parsed-literal:: - - -23 5 - - -``pow`` -~~~~~~~ - -.. code:: python - - J('2 10 pow') - - -.. parsed-literal:: - - 1024 - - -``sqr`` ``sqrt`` -~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 sqr') - - -.. parsed-literal:: - - 529 - - -.. code:: python - - J('23 sqrt') - - -.. parsed-literal:: - - 4.795831523312719 - - -``++`` ``succ`` ``--`` ``pred`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 ++') - - -.. parsed-literal:: - - 2 - - -.. code:: python - - J('1 --') - - -.. parsed-literal:: - - 0 - - -``<<`` ``lshift`` ``>>`` ``rshift`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('8 1 <<') - - -.. parsed-literal:: - - 16 - - -.. code:: python - - J('8 1 >>') - - -.. parsed-literal:: - - 4 - - -``average`` -~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 5] average') - - -.. parsed-literal:: - - 2.75 - - -``range`` ``range_to_zero`` ``down_to_zero`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('5 range') - - -.. parsed-literal:: - - [4 3 2 1 0] - - -.. code:: python - - J('5 range_to_zero') - - -.. parsed-literal:: - - [0 1 2 3 4 5] - - -.. code:: python - - J('5 down_to_zero') - - -.. parsed-literal:: - - 5 4 3 2 1 0 - - -``product`` -~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 5] product') - - -.. parsed-literal:: - - 30 - - -``sum`` -~~~~~~~ - -.. code:: python - - J('[1 2 3 5] sum') - - -.. parsed-literal:: - - 11 - - -``min`` -~~~~~~~ - -.. code:: python - - J('[1 2 3 5] min') - - -.. parsed-literal:: - - 1 - - -``gcd`` -~~~~~~~ - -.. code:: python - - J('45 30 gcd') - - -.. parsed-literal:: - - 15 - - -``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. - -.. code:: python - - J('[45 30] least_fraction') - - -.. parsed-literal:: - - [3 2] - - -.. code:: python - - J('[23 12] least_fraction') - - -.. parsed-literal:: - - [23 12] - - -Logic and Comparison -==================== - -``?`` ``truthy`` -~~~~~~~~~~~~~~~~ - -Get the Boolean value of the item on the top of the stack. - -.. code:: python - - J('23 truthy') - - -.. parsed-literal:: - - True - - -.. code:: python - - J('[] truthy') # Python semantics. - - -.. parsed-literal:: - - False - - -.. code:: python - - J('0 truthy') - - -.. parsed-literal:: - - False - - -:: - - ? == dup truthy - -.. code:: python - - V('23 ?') - - -.. parsed-literal:: - - . 23 ? - 23 . ? - 23 . dup truthy - 23 23 . truthy - 23 True . - - -.. code:: python - - J('[] ?') - - -.. parsed-literal:: - - [] False - - -.. code:: python - - J('0 ?') - - -.. parsed-literal:: - - 0 False - - -``&`` ``and`` -~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 &') - - -.. parsed-literal:: - - 1 - - -``!=`` ``<>`` ``ne`` -~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 !=') - - -.. parsed-literal:: - - True - - -| The usual suspects: - ``<`` ``lt`` - ``<=`` ``le`` -| - ``=`` ``eq`` - ``>`` ``gt`` - ``>=`` ``ge`` - ``not`` - ``or`` - -``^`` ``xor`` -~~~~~~~~~~~~~ - -.. code:: python - - J('1 1 ^') - - -.. parsed-literal:: - - 0 - - -.. code:: python - - J('1 0 ^') - - -.. parsed-literal:: - - 1 - - -Miscellaneous -============= - -``help`` -~~~~~~~~ - -.. code:: python - - J('[help] help') - - -.. parsed-literal:: - - Accepts a quoted symbol on the top of the stack and prints its docs. - - - -``parse`` -~~~~~~~~~ - -.. code:: python - - J('[parse] help') - - -.. parsed-literal:: - - Parse the string on the stack to a Joy expression. - - - -.. code:: python - - J('1 "2 [3] dup" parse') - - -.. parsed-literal:: - - 1 [2 [3] dup] - - -``run`` -~~~~~~~ - -Evaluate a quoted Joy sequence. - -.. code:: python - - J('[1 2 dup + +] run') - - -.. parsed-literal:: - - [5] - - -Combinators -=========== - -``app1`` ``app2`` ``app3`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[app1] help') - - -.. parsed-literal:: - - Given a quoted program on TOS and anything as the second stack item run - the program and replace the two args with the first result of the - program. - - ... x [Q] . app1 - ----------------------------------- - ... [x ...] [Q] . infra first - - - -.. code:: python - - J('10 4 [sqr *] app1') - - -.. parsed-literal:: - - 10 160 - - -.. code:: python - - J('10 3 4 [sqr *] app2') - - -.. parsed-literal:: - - 10 90 160 - - -.. code:: python - - J('[app2] help') - - -.. parsed-literal:: - - Like app1 with two items. - - ... y x [Q] . app2 - ----------------------------------- - ... [y ...] [Q] . infra first - [x ...] [Q] infra first - - - -.. code:: python - - J('10 2 3 4 [sqr *] app3') - - -.. parsed-literal:: - - 10 40 90 160 - - -``anamorphism`` -~~~~~~~~~~~~~~~ - -Given an initial value, a predicate function ``[P]``, and a generator -function ``[G]``, the ``anamorphism`` combinator creates a sequence. - -:: - - n [P] [G] anamorphism - --------------------------- - [...] - -Example, ``range``: - -:: - - range == [0 <=] [1 - dup] anamorphism - -.. code:: python - - J('3 [0 <=] [1 - dup] anamorphism') - - -.. parsed-literal:: - - [2 1 0] - - -``branch`` -~~~~~~~~~~ - -.. code:: python - - J('3 4 1 [+] [*] branch') - - -.. parsed-literal:: - - 12 - - -.. code:: python - - J('3 4 0 [+] [*] branch') - - -.. parsed-literal:: - - 7 - - -``cleave`` -~~~~~~~~~~ - -:: - - ... x [P] [Q] cleave - -From the original Joy docs: "The cleave combinator expects two -quotations, and below that an item ``x`` It first executes ``[P]``, with -``x`` on top, and saves the top result element. Then it executes -``[Q]``, again with ``x``, and saves the top result. Finally it restores -the stack to what it was below ``x`` and pushes the two results P(X) and -Q(X)." - -Note that ``P`` and ``Q`` can use items from the stack freely, since the -stack (below ``x``) is restored. ``cleave`` is a kind of *parallel* -primitive, and it would make sense to create a version that uses, e.g. -Python threads or something, to actually run ``P`` and ``Q`` -concurrently. The current implementation of ``cleave`` is a definition -in terms of ``app2``: - -:: - - cleave == [i] app2 [popd] dip - -.. code:: python - - J('10 2 [+] [-] cleave') - - -.. parsed-literal:: - - 10 12 8 - - -``dip`` ``dipd`` ``dipdd`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 4 5 [+] dip') - - -.. parsed-literal:: - - 1 2 7 5 - - -.. code:: python - - J('1 2 3 4 5 [+] dipd') - - -.. parsed-literal:: - - 1 5 4 5 - - -.. code:: python - - J('1 2 3 4 5 [+] dipdd') - - -.. parsed-literal:: - - 3 3 4 5 - - -``dupdip`` -~~~~~~~~~~ - -Expects a quoted program ``[Q]`` on the stack and some item under it, -``dup`` the item and ``dip`` the quoted program under it. - -:: - - n [Q] dupdip == n Q n - -.. code:: python - - V('23 [++] dupdip *') # N(N + 1) - - -.. parsed-literal:: - - . 23 [++] dupdip * - 23 . [++] dupdip * - 23 [++] . dupdip * - 23 . ++ 23 * - 24 . 23 * - 24 23 . * - 552 . - - -``genrec`` ``primrec`` -~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[genrec] help') - - -.. parsed-literal:: - - General Recursion Combinator. - - [if] [then] [rec1] [rec2] genrec - --------------------------------------------------------------------- - [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte - - From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun: - "The genrec combinator takes four program parameters in addition to - whatever data parameters it needs. Fourth from the top is an if-part, - followed by a then-part. If the if-part yields true, then the then-part - is executed and the combinator terminates. The other two parameters are - the rec1-part and the rec2-part. If the if-part yields false, the - rec1-part is executed. Following that the four program parameters and - the combinator are again pushed onto the stack bundled up in a quoted - form. Then the rec2-part is executed, where it will find the bundled - form. Typically it will then execute the bundled form, either with i or - with app2, or some other combinator." - - The way to design one of these is to fix your base case [then] and the - test [if], and then treat rec1 and rec2 as an else-part "sandwiching" - a quotation of the whole function. - - For example, given a (general recursive) function 'F': - - F == [I] [T] [R1] [R2] genrec - - If the [I] if-part fails you must derive R1 and R2 from: - - ... R1 [F] R2 - - Just set the stack arguments in front, and figure out what R1 and R2 - have to do to apply the quoted [F] in the proper way. In effect, the - genrec combinator turns into an ifte combinator with a quoted copy of - the original definition in the else-part: - - F == [I] [T] [R1] [R2] genrec - == [I] [T] [R1 [F] R2] ifte - - (Primitive recursive functions are those where R2 == i. - - P == [I] [T] [R] primrec - == [I] [T] [R [P] i] ifte - == [I] [T] [R P] ifte - ) - - - -.. code:: python - - J('3 [1 <=] [] [dup --] [i *] genrec') - - -.. parsed-literal:: - - 6 - - -``i`` -~~~~~ - -.. code:: python - - V('1 2 3 [+ +] i') - - -.. parsed-literal:: - - . 1 2 3 [+ +] i - 1 . 2 3 [+ +] i - 1 2 . 3 [+ +] i - 1 2 3 . [+ +] i - 1 2 3 [+ +] . i - 1 2 3 . + + - 1 5 . + - 6 . - - -``ifte`` -~~~~~~~~ - -:: - - [predicate] [then] [else] ifte - -.. code:: python - - J('1 2 [1] [+] [*] ifte') - - -.. parsed-literal:: - - 3 - - -.. code:: python - - J('1 2 [0] [+] [*] ifte') - - -.. parsed-literal:: - - 2 - - -``infra`` -~~~~~~~~~ - -.. code:: python - - V('1 2 3 [4 5 6] [* +] infra') - - -.. parsed-literal:: - - . 1 2 3 [4 5 6] [* +] infra - 1 . 2 3 [4 5 6] [* +] infra - 1 2 . 3 [4 5 6] [* +] infra - 1 2 3 . [4 5 6] [* +] infra - 1 2 3 [4 5 6] . [* +] infra - 1 2 3 [4 5 6] [* +] . infra - 6 5 4 . * + [3 2 1] swaack - 6 20 . + [3 2 1] swaack - 26 . [3 2 1] swaack - 26 [3 2 1] . swaack - 1 2 3 [26] . - - -``loop`` -~~~~~~~~ - -.. code:: python - - J('[loop] help') - - -.. parsed-literal:: - - Basic loop combinator. - - ... True [Q] loop - ----------------------- - ... Q [Q] loop - - ... False [Q] loop - ------------------------ - ... - - - -.. code:: python - - V('3 dup [1 - dup] loop') - - -.. parsed-literal:: - - . 3 dup [1 - dup] loop - 3 . dup [1 - dup] loop - 3 3 . [1 - dup] loop - 3 3 [1 - dup] . loop - 3 . 1 - dup [1 - dup] loop - 3 1 . - dup [1 - dup] loop - 2 . dup [1 - dup] loop - 2 2 . [1 - dup] loop - 2 2 [1 - dup] . loop - 2 . 1 - dup [1 - dup] loop - 2 1 . - dup [1 - dup] loop - 1 . dup [1 - dup] loop - 1 1 . [1 - dup] loop - 1 1 [1 - dup] . loop - 1 . 1 - dup [1 - dup] loop - 1 1 . - dup [1 - dup] loop - 0 . dup [1 - dup] loop - 0 0 . [1 - dup] loop - 0 0 [1 - dup] . loop - 0 . - - -``map`` ``pam`` -~~~~~~~~~~~~~~~ - -.. code:: python - - J('10 [1 2 3] [*] map') - - -.. parsed-literal:: - - 10 [10 20 30] - - -.. code:: python - - J('10 5 [[*][/][+][-]] pam') - - -.. parsed-literal:: - - 10 5 [50 2.0 15 5] - - -``nullary`` ``unary`` ``binary`` ``ternary`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Run a quoted program enforcing -`arity `__. - -.. code:: python - - J('1 2 3 4 5 [+] nullary') - - -.. parsed-literal:: - - 1 2 3 4 5 9 - - -.. code:: python - - J('1 2 3 4 5 [+] unary') - - -.. parsed-literal:: - - 1 2 3 4 9 - - -.. code:: python - - J('1 2 3 4 5 [+] binary') # + has arity 2 so this is technically pointless... - - -.. parsed-literal:: - - 1 2 3 9 - - -.. code:: python - - J('1 2 3 4 5 [+] ternary') - - -.. parsed-literal:: - - 1 2 9 - - -``step`` -~~~~~~~~ - -.. code:: python - - J('[step] help') - - -.. parsed-literal:: - - Run a quoted program on each item in a sequence. - - ... [] [Q] . step - ----------------------- - ... . - - - ... [a] [Q] . step - ------------------------ - ... a . Q - - - ... [a b c] [Q] . step - ---------------------------------------- - ... a . Q [b c] [Q] step - - The step combinator executes the quotation on each member of the list - on top of the stack. - - - -.. code:: python - - V('0 [1 2 3] [+] step') - - -.. parsed-literal:: - - . 0 [1 2 3] [+] step - 0 . [1 2 3] [+] step - 0 [1 2 3] . [+] step - 0 [1 2 3] [+] . step - 0 1 [+] . i [2 3] [+] step - 0 1 . + [2 3] [+] step - 1 . [2 3] [+] step - 1 [2 3] . [+] step - 1 [2 3] [+] . step - 1 2 [+] . i [3] [+] step - 1 2 . + [3] [+] step - 3 . [3] [+] step - 3 [3] . [+] step - 3 [3] [+] . step - 3 3 [+] . i - 3 3 . + - 6 . - - -``times`` -~~~~~~~~~ - -.. code:: python - - V('3 2 1 2 [+] times') - - -.. parsed-literal:: - - . 3 2 1 2 [+] times - 3 . 2 1 2 [+] times - 3 2 . 1 2 [+] times - 3 2 1 . 2 [+] times - 3 2 1 2 . [+] times - 3 2 1 2 [+] . times - 3 2 1 . + 1 [+] times - 3 3 . 1 [+] times - 3 3 1 . [+] times - 3 3 1 [+] . times - 3 3 . + - 6 . - - -``b`` -~~~~~ - -.. code:: python - - J('[b] help') - - -.. parsed-literal:: - - b == [i] dip i - - ... [P] [Q] b == ... [P] i [Q] i - ... [P] [Q] b == ... P Q - - - -.. code:: python - - V('1 2 [3] [4] b') - - -.. parsed-literal:: - - . 1 2 [3] [4] b - 1 . 2 [3] [4] b - 1 2 . [3] [4] b - 1 2 [3] . [4] b - 1 2 [3] [4] . b - 1 2 . 3 4 - 1 2 3 . 4 - 1 2 3 4 . - - -``while`` -~~~~~~~~~ - -:: - - [predicate] [body] while - -.. code:: python - - J('3 [0 >] [dup --] while') - - -.. parsed-literal:: - - 3 2 1 0 - - -``x`` -~~~~~ - -.. code:: python - - J('[x] help') - - -.. parsed-literal:: - - x == dup i - - ... [Q] x = ... [Q] dup i - ... [Q] x = ... [Q] [Q] i - ... [Q] x = ... [Q] Q - - - -.. code:: python - - V('1 [2] [i 3] x') # Kind of a pointless example. - - -.. parsed-literal:: - - . 1 [2] [i 3] x - 1 . [2] [i 3] x - 1 [2] . [i 3] x - 1 [2] [i 3] . x - 1 [2] [i 3] . i 3 - 1 [2] . i 3 3 - 1 . 2 3 3 - 1 2 . 3 3 - 1 2 3 . 3 - 1 2 3 3 . - - -``void`` -======== - -Implements `**Laws of Form** -*arithmetic* `__ -over quote-only datastructures (that is, datastructures that consist -soley of containers, without strings or numbers or anything else.) - -.. code:: python - - J('[] void') - - -.. parsed-literal:: - - False - - -.. code:: python - - J('[[]] void') - - -.. parsed-literal:: - - True - - -.. code:: python - - J('[[][[]]] void') - - -.. parsed-literal:: - - True - - -.. code:: python - - J('[[[]][[][]]] void') - - -.. parsed-literal:: - - False - diff --git a/docs/sphinx_docs/_build/html/_sources/library.rst.txt b/docs/sphinx_docs/_build/html/_sources/library.rst.txt deleted file mode 100644 index 63a621e..0000000 --- a/docs/sphinx_docs/_build/html/_sources/library.rst.txt +++ /dev/null @@ -1,19 +0,0 @@ - -Function Reference -====================================== - - -``joy.library`` ----------------------- - - -.. automodule:: joy.library - :members: - - -Auto-generated Functions ---------------------------- - -.. automodule:: joy.utils.generated_library - :members: - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Categorical.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Categorical.rst.txt deleted file mode 100644 index 979ec20..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Categorical.rst.txt +++ /dev/null @@ -1,17 +0,0 @@ - -*********************** -Categorical Programming -*********************** - -DRAFT - -`Categorical `__ - -In Manfred von Thun's article `Joy compared with other functional languages `__ he asks, "Could the language of categories be used for writing programs? Any lambda expression can be translated into a categorical expression, so the language of categories is expressively complete. But this does not make it a suitable language for writing programs. As it stands it is a very low-level language." - -In `Compiling to categories `__ Conal Elliott give a taste of what this might mean. - - It is well-known that the simply typed lambda-calculus is modeled by any cartesian closed category (CCC). This correspondence suggests giving typed functional programs a variety of interpretations, each corresponding to a different category. A convenient way to realize this idea is as a collection of meaning-preserving transformations added to an existing compiler, such as GHC for Haskell. This paper describes such an implementation and demonstrates its use for a variety of interpretations including hardware circuits, automatic differentiation, incremental computation, and interval analysis. Each such interpretation is a category easily defined in Haskell (outside of the compiler). The general technique appears to provide a compelling alternative to deeply embedded domain-specific languages. - -What he's doing is translating lambda forms into a kind of "point-free" style that is very close to Joy code (although more verbose) and then showing how to instantiate that code over different categories to get several different kinds of program out of the same code. - 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 deleted file mode 100644 index 68d6363..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Derivatives_of_Regular_Expressions.rst.txt +++ /dev/null @@ -1,946 +0,0 @@ -∂RE -=== - -Brzozowski’s Derivatives of Regular Expressions ------------------------------------------------ - -Legend: - -:: - - ∧ intersection - ∨ union - ∘ concatenation (see below) - ¬ complement - ϕ empty set (aka ∅) - λ singleton set containing just the empty string - I set of all letters in alphabet - -Derivative of a set ``R`` of strings and a string ``a``: - -:: - - ∂a(R) - - ∂a(a) → λ - ∂a(λ) → ϕ - ∂a(ϕ) → ϕ - ∂a(¬a) → ϕ - ∂a(R*) → ∂a(R)∘R* - ∂a(¬R) → ¬∂a(R) - ∂a(R∘S) → ∂a(R)∘S ∨ δ(R)∘∂a(S) - ∂a(R ∧ S) → ∂a(R) ∧ ∂a(S) - ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S) - - ∂ab(R) = ∂b(∂a(R)) - -Auxiliary predicate function ``δ`` (I call it ``nully``) returns either -``λ`` if ``λ ⊆ R`` or ``ϕ`` otherwise: - -:: - - δ(a) → ϕ - δ(λ) → λ - δ(ϕ) → ϕ - δ(R*) → λ - δ(¬R) δ(R)≟ϕ → λ - δ(¬R) δ(R)≟λ → ϕ - δ(R∘S) → δ(R) ∧ δ(S) - δ(R ∧ S) → δ(R) ∧ δ(S) - δ(R ∨ S) → δ(R) ∨ δ(S) - -Some rules we will use later for “compaction”: - -:: - - R ∧ ϕ = ϕ ∧ R = ϕ - - R ∧ I = I ∧ R = R - - R ∨ ϕ = ϕ ∨ R = R - - R ∨ I = I ∨ R = I - - R∘ϕ = ϕ∘R = ϕ - - R∘λ = λ∘R = R - -Concatination of sets: for two sets A and B the set A∘B is defined as: - -{a∘b for a in A for b in B} - -E.g.: - -{‘a’, ‘b’}∘{‘c’, ‘d’} → {‘ac’, ‘ad’, ‘bc’, ‘bd’} - -Implementation --------------- - -.. code:: ipython2 - - from functools import partial as curry - from itertools import product - -``ϕ`` and ``λ`` -~~~~~~~~~~~~~~~ - -The empty set and the set of just the empty string. - -.. code:: ipython2 - - phi = frozenset() # ϕ - y = frozenset({''}) # λ - -Two-letter Alphabet -~~~~~~~~~~~~~~~~~~~ - -I’m only going to use two symbols (at first) becaase this is enough to -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. - -.. code:: ipython2 - - syms = O, l = frozenset({'0'}), frozenset({'1'}) - -Representing Regular Expressions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To represent REs in Python I’m going to use tagged tuples. A *regular -expression* is one of: - -:: - - O - l - (KSTAR, R) - (NOT, R) - (AND, R, S) - (CONS, R, S) - (OR, R, S) - -Where ``R`` and ``S`` stand for *regular expressions*. - -.. code:: ipython2 - - AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split() # Tags are just strings. - -Because they are formed of ``frozenset``, ``tuple`` and ``str`` objects -only, these datastructures are immutable. - -String Representation of RE Datastructures -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: ipython2 - - 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 - -``I`` -~~~~~ - -Match anything. Often spelled “.” - -:: - - I = (0|1)* - -.. code:: ipython2 - - I = (KSTAR, (OR, O, l)) - -.. code:: ipython2 - - print stringy(I) - - -.. parsed-literal:: - - . - - -``(.111.) & (.01 + 11*)'`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The example expression from Brzozowski: - -:: - - (.111.) & (.01 + 11*)' - a & (b + c)' - -Note that it contains one of everything. - -.. code:: ipython2 - - a = (CONS, I, (CONS, l, (CONS, l, (CONS, l, I)))) - b = (CONS, I, (CONS, O, l)) - c = (CONS, l, (KSTAR, l)) - it = (AND, a, (NOT, (OR, b, c))) - -.. code:: ipython2 - - print stringy(it) - - -.. parsed-literal:: - - (.111.) & ((.01 | 11*)') - - -``nully()`` -~~~~~~~~~~~ - -Let’s get that auxiliary predicate function ``δ`` out of the way. - -.. code:: ipython2 - - def nully(R): - ''' - δ - Return λ if λ ⊆ R otherwise ϕ. - ''' - - # δ(a) → ϕ - # δ(ϕ) → ϕ - if R in syms or R == phi: - return phi - - # δ(λ) → λ - if R == y: - return y - - tag = R[0] - - # δ(R*) → λ - if tag == KSTAR: - return 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 - -No “Compaction” -~~~~~~~~~~~~~~~ - -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 - - def D(symbol): - - def derv(R): - - # ∂a(a) → λ - if R == {symbol}: - return y - - # ∂a(λ) → ϕ - # ∂a(ϕ) → ϕ - # ∂a(¬a) → ϕ - if R == y or R == phi or R in syms: - return phi - - tag = R[0] - - # ∂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])) - - 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) ∧ ∂a(S) - # ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S) - return (tag, derv(r), derv(s)) - - return derv - -Compaction Rules -~~~~~~~~~~~~~~~~ - -.. code:: ipython2 - - 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. - -.. code:: ipython2 - - # 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∘ϕ = ϕ∘R = ϕ - _cons = curry(_compaction_rule, CONS, y, phi) - -Memoizing -~~~~~~~~~ - -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 - - class Memo(object): - - 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 - -With “Compaction” -~~~~~~~~~~~~~~~~~ - -This version uses the rules above to perform compaction. It keeps the -expressions from growing too large. - -.. code:: ipython2 - - def D_compaction(symbol): - - @Memo - def derv(R): - - # ∂a(a) → λ - if R == {symbol}: - return y - - # ∂a(λ) → ϕ - # ∂a(ϕ) → ϕ - # ∂a(¬a) → ϕ - if R == y or R == phi or R in syms: - return phi - - tag = R[0] - - # ∂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])) - - 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) ∧ ∂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 - -Let’s try it out… ------------------ - -(FIXME: redo.) - -.. code:: ipython2 - - 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 - - -.. parsed-literal:: - - (.111.) & ((.01 | 11*)') - - 92 / 122 - 92 / 122 - - (.01)' - (.01 | 1)' - (.01 | ^)' - (.01 | 1*)' - (.111.) & ((.01 | 1)') - (.111. | 11.) & ((.01 | ^)') - (.111. | 11. | 1.) & ((.01)') - (.111. | 11.) & ((.01 | 1*)') - (.111. | 11. | 1.) & ((.01 | 1*)') - - -Should match: - -:: - - (.111.) & ((.01 | 11*)') - - 92 / 122 - 92 / 122 - - (.01 )' - (.01 | 1 )' - (.01 | ^ )' - (.01 | 1*)' - (.111.) & ((.01 | 1 )') - (.111. | 11.) & ((.01 | ^ )') - (.111. | 11.) & ((.01 | 1*)') - (.111. | 11. | 1.) & ((.01 )') - (.111. | 11. | 1.) & ((.01 | 1*)') - -Larger Alphabets ----------------- - -We could parse larger alphabets by defining patterns for e.g. each byte -of the ASCII code. Or we can generalize this code. If you study the code -above you’ll see that we never use the “set-ness” of the symbols ``O`` -and ``l``. The only time Python set operators (``&`` and ``|``) appear -is in the ``nully()`` function, and there they operate on (recursively -computed) outputs of that function, never ``O`` and ``l``. - -What if we try: - -:: - - (OR, O, l) - - ∂1((OR, O, l)) - ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S) - ∂1(O) ∨ ∂1(l) - ∂a(¬a) → ϕ - ϕ ∨ ∂1(l) - ∂a(a) → λ - ϕ ∨ λ - ϕ ∨ R = R - λ - -And compare it to: - -:: - - {'0', '1') - - ∂1({'0', '1')) - ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S) - ∂1({'0')) ∨ ∂1({'1')) - ∂a(¬a) → ϕ - ϕ ∨ ∂1({'1')) - ∂a(a) → λ - ϕ ∨ λ - ϕ ∨ R = R - λ - -This suggests that we should be able to alter the functions above to -detect sets and deal with them appropriately. Exercise for the Reader -for now. - -State Machine -------------- - -We can drive the regular expressions to flesh out the underlying state -machine transition table. - -:: - - .111. & (.01 + 11*)' - -Says, “Three or more 1’s and not ending in 01 nor composed of all 1’s.” - -.. figure:: omg.svg - :alt: State Machine Graph - - State Machine Graph - -Start at ``a`` and follow the transition arrows according to their -labels. Accepting states have a double outline. (Graphic generated with -`Dot from Graphviz `__.) You’ll see that only -paths that lead to one of the accepting states will match the regular -expression. All other paths will terminate at one of the non-accepting -states. - -There’s a happy path to ``g`` along 111: - -:: - - a→c→e→g - -After you reach ``g`` you’re stuck there eating 1’s until you see a 0, -which takes you to the ``i→j→i|i→j→h→i`` “trap”. You can’t reach any -other states from those two loops. - -If you see a 0 before you see 111 you will reach ``b``, which forms -another “trap” with ``d`` and ``f``. The only way out is another happy -path along 111 to ``h``: - -:: - - b→d→f→h - -Once you have reached ``h`` you can see as many 1’s or as many 0’ in a -row and still be either still at ``h`` (for 1’s) or move to ``i`` (for -0’s). If you find yourself at ``i`` you can see as many 0’s, or -repetitions of 10, as there are, but if you see just a 1 you move to -``j``. - -RE to FSM -~~~~~~~~~ - -So how do we get the state machine from the regular expression? - -It turns out that each RE is effectively a state, and each arrow points -to the derivative RE in respect to the arrow’s symbol. - -If we label the initial RE ``a``, we can say: - -:: - - a --0--> ∂0(a) - a --1--> ∂1(a) - -And so on, each new unique RE is a new state in the FSM table. - -Here are the derived REs at each state: - -:: - - a = (.111.) & ((.01 | 11*)') - b = (.111.) & ((.01 | 1)') - c = (.111. | 11.) & ((.01 | 1*)') - d = (.111. | 11.) & ((.01 | ^)') - e = (.111. | 11. | 1.) & ((.01 | 1*)') - f = (.111. | 11. | 1.) & ((.01)') - g = (.01 | 1*)' - h = (.01)' - i = (.01 | 1)' - j = (.01 | ^)' - -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 - - from collections import defaultdict - from pprint import pprint - from string import ascii_lowercase - -.. code:: ipython2 - - d0, d1 = D_compaction('0'), D_compaction('1') - -``explore()`` -~~~~~~~~~~~~~ - -.. code:: ipython2 - - def explore(re): - - # Don't have more than 26 states... - names = defaultdict(iter(ascii_lowercase).next) - - table, accepting = dict(), set() - - to_check = {re} - while to_check: - - re = to_check.pop() - state_name = names[re] - - if (state_name, 0) in table: - continue - - 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) - - return table, accepting - -.. code:: ipython2 - - table, accepting = explore(it) - table - - - - -.. parsed-literal:: - - {('a', 0): 'b', - ('a', 1): 'c', - ('b', 0): 'b', - ('b', 1): 'd', - ('c', 0): 'b', - ('c', 1): 'e', - ('d', 0): 'b', - ('d', 1): 'f', - ('e', 0): 'b', - ('e', 1): 'g', - ('f', 0): 'b', - ('f', 1): 'h', - ('g', 0): 'i', - ('g', 1): 'g', - ('h', 0): 'i', - ('h', 1): 'h', - ('i', 0): 'i', - ('i', 1): 'j', - ('j', 0): 'i', - ('j', 1): 'h'} - - - -.. code:: ipython2 - - accepting - - - - -.. parsed-literal:: - - {'h', 'i'} - - - -Generate Diagram -~~~~~~~~~~~~~~~~ - -Once we have the FSM table and the set of accepting states we can -generate the diagram above. - -.. code:: ipython2 - - _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 make_graph(table, accepting): - return _template % ( - ' '.join(accepting), - '\n'.join( - link(from_, to, char) - for (from_, char), (to) in sorted(table.iteritems()) - ) - ) - -.. code:: ipython2 - - print make_graph(table, accepting) - - -.. parsed-literal:: - - digraph finite_state_machine { - rankdir=LR; - size="8,5" - node [shape = doublecircle]; i h; - node [shape = circle]; - a -> b [ label = "0" ]; - a -> c [ label = "1" ]; - b -> b [ label = "0" ]; - b -> d [ label = "1" ]; - c -> b [ label = "0" ]; - c -> e [ label = "1" ]; - d -> b [ label = "0" ]; - d -> f [ label = "1" ]; - e -> b [ label = "0" ]; - e -> g [ label = "1" ]; - f -> b [ label = "0" ]; - f -> h [ label = "1" ]; - g -> i [ label = "0" ]; - g -> g [ label = "1" ]; - h -> i [ label = "0" ]; - h -> h [ label = "1" ]; - i -> i [ label = "0" ]; - i -> j [ label = "1" ]; - j -> i [ label = "0" ]; - j -> h [ label = "1" ]; - } - - - -Drive a FSM -~~~~~~~~~~~ - -There are *lots* of FSM libraries already. Once you have the state -transition table they should all be straightforward to use. State -Machine code is very simple. Just for fun, here is an implementation in -Python that imitates what “compiled” FSM code might look like in an -“unrolled” form. Most FSM code uses a little driver loop and a table -datastructure, the code below instead acts like JMP instructions -(“jump”, or GOTO in higher-level-but-still-low-level languages) to -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. - -.. code:: ipython2 - - 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 - -Stream Functions -^^^^^^^^^^^^^^^^ - -Little helpers to process the iterator of our data (a “stream” of “1” -and “0” characters, not bits.) - -.. code:: ipython2 - - getch = lambda I: int(next(I)) - - - def _1(I): - '''Loop on ones.''' - while getch(I): pass - - - def _0(I): - '''Loop on zeros.''' - while not getch(I): pass - -A Finite State Machine -^^^^^^^^^^^^^^^^^^^^^^ - -With those preliminaries out of the way, from the state table of -``.111. & (.01 + 11*)'`` we can immediately write down state machine -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 - - 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. - -.. code:: ipython2 - - def acceptable(input_): - return trampoline(input_, a, {h, i}) - -.. code:: ipython2 - - for n in range(2**5): - s = bin(n)[2:] - print '%05s' % s, acceptable(s) - - -.. parsed-literal:: - - 0 False - 1 False - 10 False - 11 False - 100 False - 101 False - 110 False - 111 False - 1000 False - 1001 False - 1010 False - 1011 False - 1100 False - 1101 False - 1110 True - 1111 False - 10000 False - 10001 False - 10010 False - 10011 False - 10100 False - 10101 False - 10110 False - 10111 True - 11000 False - 11001 False - 11010 False - 11011 False - 11100 True - 11101 False - 11110 True - 11111 False - - -Reversing the Derivatives to Generate Matching Strings ------------------------------------------------------- - -(UNFINISHED) Brzozowski also shewed how to go from the state machine to -strings and expressions… - -Each of these states is just a name for a Brzozowskian RE, and so, other -than the initial state ``a``, they can can be described in terms of the -derivative-with-respect-to-N of some other state/RE: - -:: - - c = d1(a) - b = d0(a) - b = d0(c) - ... - i = d0(j) - j = d1(i) - -Consider: - -:: - - c = d1(a) - b = d0(c) - -Substituting: - -:: - - b = d0(d1(a)) - -Unwrapping: - -:: - - b = d10(a) - -’’’ - -:: - - j = d1(d0(j)) - -Unwrapping: - -:: - - j = d1(d0(j)) = d01(j) - -We have a loop or “fixed point”. - -:: - - j = d01(j) = d0101(j) = d010101(j) = ... - -hmm… - -:: - - j = (01)* - - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Developing.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Developing.rst.txt deleted file mode 100644 index 556225a..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Developing.rst.txt +++ /dev/null @@ -1,815 +0,0 @@ -*************************** -Developing a Program in Joy -*************************** - -As an example of developing a program in Joy let's take the first problem from the Project Euler website. - -`Project Euler, first problem: "Multiples of 3 and 5" `__ -============================================================================================= - - - 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. - -.. code:: python - - 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. - -.. code:: python - - define('P == [3 % not] dupdip 5 % not or') - -.. code:: python - - V('80 P') - - -.. parsed-literal:: - - . 80 P - 80 . P - 80 . [3 % not] dupdip 5 % not or - 80 [3 % not] . dupdip 5 % not or - 80 . 3 % not 80 5 % not or - 80 3 . % not 80 5 % not or - 2 . not 80 5 % not or - False . 80 5 % not or - False 80 . 5 % not or - False 80 5 . % not or - False 0 . not or - False True . or - True . - - -Given the predicate function ``P`` a suitable program is: - -:: - - PE1 == 1000 range [P] filter sum - -This function generates a list of the integers from 0 to 999, filters -that list by ``P``, and then sums the result. - -Logically this is fine, but pragmatically we are doing more work than we -should be; we generate one thousand integers but actually use less than -half of them. A better solution would be to generate just the multiples -we want to sum, and to add them as we go rather than storing them and -and summing them at the end. - -Generate just the multiples -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -At first I had the idea to use two counters and increase them by three -and five, respectively. This way we only generate the terms that we -actually want to sum. We have to proceed by incrementing the counter -that is lower, or if they are equal, the three counter, and we have to -take care not to double add numbers like 15 that are multiples of both -three and five. - -This seemed a little clunky, so I tried a different approach. - -Consider the first few terms in the series: - -:: - - 3 5 6 9 10 12 15 18 20 21 ... - -Subtract each number from the one after it (subtracting 0 from 3): - -:: - - 3 5 6 9 10 12 15 18 20 21 24 25 27 30 ... - 0 3 5 6 9 10 12 15 18 20 21 24 25 27 ... - ------------------------------------------- - 3 2 1 3 1 2 3 3 2 1 3 1 2 3 ... - -You get this lovely repeating palindromic sequence: - -:: - - 3 2 1 3 1 2 3 - -To make a counter that increments by factors of 3 and 5 you just add -these differences to the counter one-by-one in a loop. - -To make use of this sequence to increment a counter and sum terms as we -go we need a function that will accept the sum, the counter, and the -next term to add, and that adds the term to the counter and a copy of -the counter to the running sum. This function will do that: - -:: - - PE1.1 == + [+] dupdip - -.. code:: python - - define('PE1.1 == + [+] dupdip') - -.. code:: python - - V('0 0 3 PE1.1') - - -.. parsed-literal:: - - . 0 0 3 PE1.1 - 0 . 0 3 PE1.1 - 0 0 . 3 PE1.1 - 0 0 3 . PE1.1 - 0 0 3 . + [+] dupdip - 0 3 . [+] dupdip - 0 3 [+] . dupdip - 0 3 . + 3 - 3 . 3 - 3 3 . - - -.. code:: python - - V('0 0 [3 2 1 3 1 2 3] [PE1.1] step') - - -.. parsed-literal:: - - . 0 0 [3 2 1 3 1 2 3] [PE1.1] step - 0 . 0 [3 2 1 3 1 2 3] [PE1.1] step - 0 0 . [3 2 1 3 1 2 3] [PE1.1] step - 0 0 [3 2 1 3 1 2 3] . [PE1.1] step - 0 0 [3 2 1 3 1 2 3] [PE1.1] . step - 0 0 3 [PE1.1] . i [2 1 3 1 2 3] [PE1.1] step - 0 0 3 . PE1.1 [2 1 3 1 2 3] [PE1.1] step - 0 0 3 . + [+] dupdip [2 1 3 1 2 3] [PE1.1] step - 0 3 . [+] dupdip [2 1 3 1 2 3] [PE1.1] step - 0 3 [+] . dupdip [2 1 3 1 2 3] [PE1.1] step - 0 3 . + 3 [2 1 3 1 2 3] [PE1.1] step - 3 . 3 [2 1 3 1 2 3] [PE1.1] step - 3 3 . [2 1 3 1 2 3] [PE1.1] step - 3 3 [2 1 3 1 2 3] . [PE1.1] step - 3 3 [2 1 3 1 2 3] [PE1.1] . step - 3 3 2 [PE1.1] . i [1 3 1 2 3] [PE1.1] step - 3 3 2 . PE1.1 [1 3 1 2 3] [PE1.1] step - 3 3 2 . + [+] dupdip [1 3 1 2 3] [PE1.1] step - 3 5 . [+] dupdip [1 3 1 2 3] [PE1.1] step - 3 5 [+] . dupdip [1 3 1 2 3] [PE1.1] step - 3 5 . + 5 [1 3 1 2 3] [PE1.1] step - 8 . 5 [1 3 1 2 3] [PE1.1] step - 8 5 . [1 3 1 2 3] [PE1.1] step - 8 5 [1 3 1 2 3] . [PE1.1] step - 8 5 [1 3 1 2 3] [PE1.1] . step - 8 5 1 [PE1.1] . i [3 1 2 3] [PE1.1] step - 8 5 1 . PE1.1 [3 1 2 3] [PE1.1] step - 8 5 1 . + [+] dupdip [3 1 2 3] [PE1.1] step - 8 6 . [+] dupdip [3 1 2 3] [PE1.1] step - 8 6 [+] . dupdip [3 1 2 3] [PE1.1] step - 8 6 . + 6 [3 1 2 3] [PE1.1] step - 14 . 6 [3 1 2 3] [PE1.1] step - 14 6 . [3 1 2 3] [PE1.1] step - 14 6 [3 1 2 3] . [PE1.1] step - 14 6 [3 1 2 3] [PE1.1] . step - 14 6 3 [PE1.1] . i [1 2 3] [PE1.1] step - 14 6 3 . PE1.1 [1 2 3] [PE1.1] step - 14 6 3 . + [+] dupdip [1 2 3] [PE1.1] step - 14 9 . [+] dupdip [1 2 3] [PE1.1] step - 14 9 [+] . dupdip [1 2 3] [PE1.1] step - 14 9 . + 9 [1 2 3] [PE1.1] step - 23 . 9 [1 2 3] [PE1.1] step - 23 9 . [1 2 3] [PE1.1] step - 23 9 [1 2 3] . [PE1.1] step - 23 9 [1 2 3] [PE1.1] . step - 23 9 1 [PE1.1] . i [2 3] [PE1.1] step - 23 9 1 . PE1.1 [2 3] [PE1.1] step - 23 9 1 . + [+] dupdip [2 3] [PE1.1] step - 23 10 . [+] dupdip [2 3] [PE1.1] step - 23 10 [+] . dupdip [2 3] [PE1.1] step - 23 10 . + 10 [2 3] [PE1.1] step - 33 . 10 [2 3] [PE1.1] step - 33 10 . [2 3] [PE1.1] step - 33 10 [2 3] . [PE1.1] step - 33 10 [2 3] [PE1.1] . step - 33 10 2 [PE1.1] . i [3] [PE1.1] step - 33 10 2 . PE1.1 [3] [PE1.1] step - 33 10 2 . + [+] dupdip [3] [PE1.1] step - 33 12 . [+] dupdip [3] [PE1.1] step - 33 12 [+] . dupdip [3] [PE1.1] step - 33 12 . + 12 [3] [PE1.1] step - 45 . 12 [3] [PE1.1] step - 45 12 . [3] [PE1.1] step - 45 12 [3] . [PE1.1] step - 45 12 [3] [PE1.1] . step - 45 12 3 [PE1.1] . i - 45 12 3 . PE1.1 - 45 12 3 . + [+] dupdip - 45 15 . [+] dupdip - 45 15 [+] . dupdip - 45 15 . + 15 - 60 . 15 - 60 15 . - - -So one ``step`` through all seven terms brings the counter to 15 and the -total to 60. - -How many multiples to sum? -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code:: python - - 1000 / 15 - - - - -.. parsed-literal:: - - 66 - - - -.. code:: python - - 66 * 15 - - - - -.. parsed-literal:: - - 990 - - - -.. code:: python - - 1000 - 990 - - - - -.. parsed-literal:: - - 10 - - - -We only want the terms *less than* 1000. - -.. code:: python - - 999 - 990 - - - - -.. parsed-literal:: - - 9 - - - -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:: 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:: python - - J('PE1') - - -.. parsed-literal:: - - 233168 - -Packing the terms into an integer -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This form uses no extra storage and produces no unused summands. It's -good but there's one more trick we can apply. The list of seven terms -takes up at least seven bytes. But notice that all of the terms are less -than four, and so each can fit in just two bits. We could store all -seven terms in just fourteen bits and use masking and shifts to pick out -each term as we go. This will use less space and save time loading whole -integer terms from the list. - -:: - - 3 2 1 3 1 2 3 - 0b 11 10 01 11 01 10 11 == 14811 - -.. code:: python - - 0b11100111011011 - - - - -.. parsed-literal:: - - 14811 - - - -.. code:: python - - define('PE1.2 == [3 & PE1.1] dupdip 2 >>') - -.. code:: python - - V('0 0 14811 PE1.2') - - -.. parsed-literal:: - - . 0 0 14811 PE1.2 - 0 . 0 14811 PE1.2 - 0 0 . 14811 PE1.2 - 0 0 14811 . PE1.2 - 0 0 14811 . [3 & PE1.1] dupdip 2 >> - 0 0 14811 [3 & PE1.1] . dupdip 2 >> - 0 0 14811 . 3 & PE1.1 14811 2 >> - 0 0 14811 3 . & PE1.1 14811 2 >> - 0 0 3 . PE1.1 14811 2 >> - 0 0 3 . + [+] dupdip 14811 2 >> - 0 3 . [+] dupdip 14811 2 >> - 0 3 [+] . dupdip 14811 2 >> - 0 3 . + 3 14811 2 >> - 3 . 3 14811 2 >> - 3 3 . 14811 2 >> - 3 3 14811 . 2 >> - 3 3 14811 2 . >> - 3 3 3702 . - - -.. code:: python - - V('3 3 3702 PE1.2') - - -.. parsed-literal:: - - . 3 3 3702 PE1.2 - 3 . 3 3702 PE1.2 - 3 3 . 3702 PE1.2 - 3 3 3702 . PE1.2 - 3 3 3702 . [3 & PE1.1] dupdip 2 >> - 3 3 3702 [3 & PE1.1] . dupdip 2 >> - 3 3 3702 . 3 & PE1.1 3702 2 >> - 3 3 3702 3 . & PE1.1 3702 2 >> - 3 3 2 . PE1.1 3702 2 >> - 3 3 2 . + [+] dupdip 3702 2 >> - 3 5 . [+] dupdip 3702 2 >> - 3 5 [+] . dupdip 3702 2 >> - 3 5 . + 5 3702 2 >> - 8 . 5 3702 2 >> - 8 5 . 3702 2 >> - 8 5 3702 . 2 >> - 8 5 3702 2 . >> - 8 5 925 . - - -.. code:: python - - V('0 0 14811 7 [PE1.2] times pop') - - -.. parsed-literal:: - - . 0 0 14811 7 [PE1.2] times pop - 0 . 0 14811 7 [PE1.2] times pop - 0 0 . 14811 7 [PE1.2] times pop - 0 0 14811 . 7 [PE1.2] times pop - 0 0 14811 7 . [PE1.2] times pop - 0 0 14811 7 [PE1.2] . times pop - 0 0 14811 [PE1.2] . i 6 [PE1.2] times pop - 0 0 14811 . PE1.2 6 [PE1.2] times pop - 0 0 14811 . [3 & PE1.1] dupdip 2 >> 6 [PE1.2] times pop - 0 0 14811 [3 & PE1.1] . dupdip 2 >> 6 [PE1.2] times pop - 0 0 14811 . 3 & PE1.1 14811 2 >> 6 [PE1.2] times pop - 0 0 14811 3 . & PE1.1 14811 2 >> 6 [PE1.2] times pop - 0 0 3 . PE1.1 14811 2 >> 6 [PE1.2] times pop - 0 0 3 . + [+] dupdip 14811 2 >> 6 [PE1.2] times pop - 0 3 . [+] dupdip 14811 2 >> 6 [PE1.2] times pop - 0 3 [+] . dupdip 14811 2 >> 6 [PE1.2] times pop - 0 3 . + 3 14811 2 >> 6 [PE1.2] times pop - 3 . 3 14811 2 >> 6 [PE1.2] times pop - 3 3 . 14811 2 >> 6 [PE1.2] times pop - 3 3 14811 . 2 >> 6 [PE1.2] times pop - 3 3 14811 2 . >> 6 [PE1.2] times pop - 3 3 3702 . 6 [PE1.2] times pop - 3 3 3702 6 . [PE1.2] times pop - 3 3 3702 6 [PE1.2] . times pop - 3 3 3702 [PE1.2] . i 5 [PE1.2] times pop - 3 3 3702 . PE1.2 5 [PE1.2] times pop - 3 3 3702 . [3 & PE1.1] dupdip 2 >> 5 [PE1.2] times pop - 3 3 3702 [3 & PE1.1] . dupdip 2 >> 5 [PE1.2] times pop - 3 3 3702 . 3 & PE1.1 3702 2 >> 5 [PE1.2] times pop - 3 3 3702 3 . & PE1.1 3702 2 >> 5 [PE1.2] times pop - 3 3 2 . PE1.1 3702 2 >> 5 [PE1.2] times pop - 3 3 2 . + [+] dupdip 3702 2 >> 5 [PE1.2] times pop - 3 5 . [+] dupdip 3702 2 >> 5 [PE1.2] times pop - 3 5 [+] . dupdip 3702 2 >> 5 [PE1.2] times pop - 3 5 . + 5 3702 2 >> 5 [PE1.2] times pop - 8 . 5 3702 2 >> 5 [PE1.2] times pop - 8 5 . 3702 2 >> 5 [PE1.2] times pop - 8 5 3702 . 2 >> 5 [PE1.2] times pop - 8 5 3702 2 . >> 5 [PE1.2] times pop - 8 5 925 . 5 [PE1.2] times pop - 8 5 925 5 . [PE1.2] times pop - 8 5 925 5 [PE1.2] . times pop - 8 5 925 [PE1.2] . i 4 [PE1.2] times pop - 8 5 925 . PE1.2 4 [PE1.2] times pop - 8 5 925 . [3 & PE1.1] dupdip 2 >> 4 [PE1.2] times pop - 8 5 925 [3 & PE1.1] . dupdip 2 >> 4 [PE1.2] times pop - 8 5 925 . 3 & PE1.1 925 2 >> 4 [PE1.2] times pop - 8 5 925 3 . & PE1.1 925 2 >> 4 [PE1.2] times pop - 8 5 1 . PE1.1 925 2 >> 4 [PE1.2] times pop - 8 5 1 . + [+] dupdip 925 2 >> 4 [PE1.2] times pop - 8 6 . [+] dupdip 925 2 >> 4 [PE1.2] times pop - 8 6 [+] . dupdip 925 2 >> 4 [PE1.2] times pop - 8 6 . + 6 925 2 >> 4 [PE1.2] times pop - 14 . 6 925 2 >> 4 [PE1.2] times pop - 14 6 . 925 2 >> 4 [PE1.2] times pop - 14 6 925 . 2 >> 4 [PE1.2] times pop - 14 6 925 2 . >> 4 [PE1.2] times pop - 14 6 231 . 4 [PE1.2] times pop - 14 6 231 4 . [PE1.2] times pop - 14 6 231 4 [PE1.2] . times pop - 14 6 231 [PE1.2] . i 3 [PE1.2] times pop - 14 6 231 . PE1.2 3 [PE1.2] times pop - 14 6 231 . [3 & PE1.1] dupdip 2 >> 3 [PE1.2] times pop - 14 6 231 [3 & PE1.1] . dupdip 2 >> 3 [PE1.2] times pop - 14 6 231 . 3 & PE1.1 231 2 >> 3 [PE1.2] times pop - 14 6 231 3 . & PE1.1 231 2 >> 3 [PE1.2] times pop - 14 6 3 . PE1.1 231 2 >> 3 [PE1.2] times pop - 14 6 3 . + [+] dupdip 231 2 >> 3 [PE1.2] times pop - 14 9 . [+] dupdip 231 2 >> 3 [PE1.2] times pop - 14 9 [+] . dupdip 231 2 >> 3 [PE1.2] times pop - 14 9 . + 9 231 2 >> 3 [PE1.2] times pop - 23 . 9 231 2 >> 3 [PE1.2] times pop - 23 9 . 231 2 >> 3 [PE1.2] times pop - 23 9 231 . 2 >> 3 [PE1.2] times pop - 23 9 231 2 . >> 3 [PE1.2] times pop - 23 9 57 . 3 [PE1.2] times pop - 23 9 57 3 . [PE1.2] times pop - 23 9 57 3 [PE1.2] . times pop - 23 9 57 [PE1.2] . i 2 [PE1.2] times pop - 23 9 57 . PE1.2 2 [PE1.2] times pop - 23 9 57 . [3 & PE1.1] dupdip 2 >> 2 [PE1.2] times pop - 23 9 57 [3 & PE1.1] . dupdip 2 >> 2 [PE1.2] times pop - 23 9 57 . 3 & PE1.1 57 2 >> 2 [PE1.2] times pop - 23 9 57 3 . & PE1.1 57 2 >> 2 [PE1.2] times pop - 23 9 1 . PE1.1 57 2 >> 2 [PE1.2] times pop - 23 9 1 . + [+] dupdip 57 2 >> 2 [PE1.2] times pop - 23 10 . [+] dupdip 57 2 >> 2 [PE1.2] times pop - 23 10 [+] . dupdip 57 2 >> 2 [PE1.2] times pop - 23 10 . + 10 57 2 >> 2 [PE1.2] times pop - 33 . 10 57 2 >> 2 [PE1.2] times pop - 33 10 . 57 2 >> 2 [PE1.2] times pop - 33 10 57 . 2 >> 2 [PE1.2] times pop - 33 10 57 2 . >> 2 [PE1.2] times pop - 33 10 14 . 2 [PE1.2] times pop - 33 10 14 2 . [PE1.2] times pop - 33 10 14 2 [PE1.2] . times pop - 33 10 14 [PE1.2] . i 1 [PE1.2] times pop - 33 10 14 . PE1.2 1 [PE1.2] times pop - 33 10 14 . [3 & PE1.1] dupdip 2 >> 1 [PE1.2] times pop - 33 10 14 [3 & PE1.1] . dupdip 2 >> 1 [PE1.2] times pop - 33 10 14 . 3 & PE1.1 14 2 >> 1 [PE1.2] times pop - 33 10 14 3 . & PE1.1 14 2 >> 1 [PE1.2] times pop - 33 10 2 . PE1.1 14 2 >> 1 [PE1.2] times pop - 33 10 2 . + [+] dupdip 14 2 >> 1 [PE1.2] times pop - 33 12 . [+] dupdip 14 2 >> 1 [PE1.2] times pop - 33 12 [+] . dupdip 14 2 >> 1 [PE1.2] times pop - 33 12 . + 12 14 2 >> 1 [PE1.2] times pop - 45 . 12 14 2 >> 1 [PE1.2] times pop - 45 12 . 14 2 >> 1 [PE1.2] times pop - 45 12 14 . 2 >> 1 [PE1.2] times pop - 45 12 14 2 . >> 1 [PE1.2] times pop - 45 12 3 . 1 [PE1.2] times pop - 45 12 3 1 . [PE1.2] times pop - 45 12 3 1 [PE1.2] . times pop - 45 12 3 [PE1.2] . i pop - 45 12 3 . PE1.2 pop - 45 12 3 . [3 & PE1.1] dupdip 2 >> pop - 45 12 3 [3 & PE1.1] . dupdip 2 >> pop - 45 12 3 . 3 & PE1.1 3 2 >> pop - 45 12 3 3 . & PE1.1 3 2 >> pop - 45 12 3 . PE1.1 3 2 >> pop - 45 12 3 . + [+] dupdip 3 2 >> pop - 45 15 . [+] dupdip 3 2 >> pop - 45 15 [+] . dupdip 3 2 >> pop - 45 15 . + 15 3 2 >> pop - 60 . 15 3 2 >> pop - 60 15 . 3 2 >> pop - 60 15 3 . 2 >> pop - 60 15 3 2 . >> pop - 60 15 0 . pop - 60 15 . - - -And so we have at last: - -.. code:: python - - define('PE1 == 0 0 66 [14811 7 [PE1.2] times pop] times 14811 4 [PE1.2] times popop') - -.. code:: python - - J('PE1') - - -.. parsed-literal:: - - 233168 - - -Let's refactor -^^^^^^^^^^^^^^^ - -:: - - 14811 7 [PE1.2] times pop - 14811 4 [PE1.2] times pop - 14811 n [PE1.2] times pop - n 14811 swap [PE1.2] times pop - -.. code:: python - - define('PE1.3 == 14811 swap [PE1.2] times pop') - -Now we can simplify the definition above: - -.. code:: python - - define('PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop') - -.. code:: python - - J('PE1') - - -.. parsed-literal:: - - 233168 - - -Here's our joy program all in one place. It doesn't make so much sense, -but if you have read through the above description of how it was derived -I hope it's clear. - -:: - - PE1.1 == + [+] dupdip - PE1.2 == [3 & PE1.1] dupdip 2 >> - PE1.3 == 14811 swap [PE1.2] times pop - PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop - -Generator Version -================= - -It's a little clunky iterating sixty-six times though the seven numbers -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:: python - - define('PE1.terms == [0 swap [dup [pop 14811] [] branch [3 &] dupdip 2 >>] dip rest cons]') - -.. code:: python - - J('PE1.terms 21 [x] times') - - -.. parsed-literal:: - - 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] - - -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:: python - - J('7 66 * 4 +') - - -.. parsed-literal:: - - 466 - - -Here they are... -~~~~~~~~~~~~~~~~ - -.. code:: python - - J('PE1.terms 466 [x] times pop') - - -.. parsed-literal:: - - 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 - - -...and they do sum to 999. -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[PE1.terms 466 [x] times pop] run sum') - - -.. parsed-literal:: - - 999 - - -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:: python - - J('0 0 PE1.terms 466 [x [PE1.1] dip] times popop') - - -.. parsed-literal:: - - 233168 - - -A little further analysis renders iteration unnecessary. -======================================================== - -Consider finding the sum of the positive integers less than or equal to -ten. - -.. code:: python - - J('[10 9 8 7 6 5 4 3 2 1] sum') - - -.. parsed-literal:: - - 55 - - -Instead of summing them, -`observe `__: - -:: - - 10 9 8 7 6 - + 1 2 3 4 5 - ---- -- -- -- -- - 11 11 11 11 11 - - 11 * 5 = 55 - -From the above example we can deduce that the sum of the first N -positive integers is: - -:: - - (N + 1) * N / 2 - -(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:: python - - define('F == dup ++ * 2 floordiv') - -.. code:: python - - V('10 F') - - -.. parsed-literal:: - - . 10 F - 10 . F - 10 . dup ++ * 2 floordiv - 10 10 . ++ * 2 floordiv - 10 11 . * 2 floordiv - 110 . 2 floordiv - 110 2 . floordiv - 55 . - - -Generalizing to Blocks of Terms -------------------------------- - -We can apply the same reasoning to the PE1 problem. - -Between 0 and 990 inclusive there are sixty-six "blocks" of seven terms -each, starting with: - -:: - - [3 5 6 9 10 12 15] - -And ending with: - -:: - - [978 980 981 984 985 987 990] - -If we reverse one of these two blocks and sum pairs... - -.. code:: python - - J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip') - - -.. parsed-literal:: - - [[978 15] [980 12] [981 10] [984 9] [985 6] [987 5] [990 3]] - - -.. code:: python - - J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map') - - -.. parsed-literal:: - - [993 992 991 993 991 992 993] - - -(Interesting that the sequence of seven numbers appears again in the -rightmost digit of each term.) - -.. code:: python - - J('[ 3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map sum') - - -.. parsed-literal:: - - 6945 - - -Since there are sixty-six blocks and we are pairing them up, there must -be thirty-three pairs, each of which sums to 6945. We also have these -additional unpaired terms between 990 and 1000: - -:: - - 993 995 996 999 - -So we can give the "sum of all the multiples of 3 or 5 below 1000" like -so: - -.. code:: python - - J('6945 33 * [993 995 996 999] cons sum') - - -.. parsed-literal:: - - 233168 - - -It's worth noting, I think, that this same reasoning holds for any two -numbers :math:`n` and :math:`m` the multiples of which we hope to sum. -The multiples would have a cycle of differences of length :math:`k` and -so we could compute the sum of :math:`Nk` multiples as above. - -The sequence of differences will always be a palidrome. Consider an -interval spanning the least common multiple of :math:`n` and :math:`m`: - -:: - - | | | | | | | | - | | | | | - -Here we have 4 and 7, and you can read off the sequence of differences -directly from the diagram: 4 3 1 4 2 2 4 1 3 4. - -Geometrically, the actual values of :math:`n` and :math:`m` and their -*lcm* don't matter, the pattern they make will always be symmetrical -around its midpoint. The same reasoning holds for multiples of more than -two numbers. - -The Simplest Program -==================== - -Of course, the simplest joy program for the first Project Euler problem -is just: - -:: - - PE1 == 233168 - -Fin. 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 deleted file mode 100644 index 55e1679..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Generator_Programs.rst.txt +++ /dev/null @@ -1,635 +0,0 @@ -Using ``x`` to Generate Values -============================== - -Cf. jp-reprod.html - -.. code:: ipython2 - - from notebook_preamble import J, V, define - -Consider the ``x`` combinator: - -:: - - x == dup i - -We can apply it to a quoted program consisting of some value ``a`` and -some function ``B``: - -:: - - [a B] x - [a B] a B - -Let ``B`` function ``swap`` the ``a`` with the quote and run some -function ``C`` on it to generate a new value ``b``: - -:: - - B == swap [C] dip - - [a B] a B - [a B] a swap [C] dip - a [a B] [C] dip - a C [a B] - b [a B] - -Now discard the quoted ``a`` with ``rest`` then ``cons`` ``b``: - -:: - - b [a B] rest cons - b [B] cons - [b B] - -Altogether, this is the definition of ``B``: - -:: - - B == swap [C] dip rest cons - -We can make a generator for the Natural numbers (0, 1, 2, …) by using -``0`` for ``a`` and ``[dup ++]`` for ``[C]``: - -:: - - [0 swap [dup ++] dip rest cons] - -Let’s try it: - -.. code:: ipython2 - - V('[0 swap [dup ++] dip rest cons] x') - - -.. parsed-literal:: - - . [0 swap [dup ++] dip rest cons] x - [0 swap [dup ++] dip rest cons] . x - [0 swap [dup ++] dip rest cons] . 0 swap [dup ++] dip rest cons - [0 swap [dup ++] dip rest cons] 0 . swap [dup ++] dip rest cons - 0 [0 swap [dup ++] dip rest cons] . [dup ++] dip rest cons - 0 [0 swap [dup ++] dip rest cons] [dup ++] . dip rest cons - 0 . dup ++ [0 swap [dup ++] dip rest cons] rest cons - 0 0 . ++ [0 swap [dup ++] dip rest cons] rest cons - 0 1 . [0 swap [dup ++] dip rest cons] rest cons - 0 1 [0 swap [dup ++] dip rest cons] . rest cons - 0 1 [swap [dup ++] dip rest cons] . cons - 0 [1 swap [dup ++] dip rest cons] . - - -After one application of ``x`` the quoted program contains ``1`` and -``0`` is below it on the stack. - -.. code:: ipython2 - - J('[0 swap [dup ++] dip rest cons] x x x x x pop') - - -.. parsed-literal:: - - 0 1 2 3 4 - - -``direco`` ----------- - -.. code:: ipython2 - - define('direco == dip rest cons') - -.. code:: ipython2 - - V('[0 swap [dup ++] direco] x') - - -.. parsed-literal:: - - . [0 swap [dup ++] direco] x - [0 swap [dup ++] direco] . x - [0 swap [dup ++] direco] . 0 swap [dup ++] direco - [0 swap [dup ++] direco] 0 . swap [dup ++] direco - 0 [0 swap [dup ++] direco] . [dup ++] direco - 0 [0 swap [dup ++] direco] [dup ++] . direco - 0 [0 swap [dup ++] direco] [dup ++] . dip rest cons - 0 . dup ++ [0 swap [dup ++] direco] rest cons - 0 0 . ++ [0 swap [dup ++] direco] rest cons - 0 1 . [0 swap [dup ++] direco] rest cons - 0 1 [0 swap [dup ++] direco] . rest cons - 0 1 [swap [dup ++] direco] . cons - 0 [1 swap [dup ++] direco] . - - -Making Generators ------------------ - -We want to define a function that accepts ``a`` and ``[C]`` and builds -our quoted program: - -:: - - a [C] G - ------------------------- - [a swap [C] direco] - -Working in reverse: - -:: - - [a swap [C] direco] cons - a [swap [C] direco] concat - a [swap] [[C] direco] swap - a [[C] direco] [swap] - a [C] [direco] cons [swap] - -Reading from the bottom up: - -:: - - G == [direco] cons [swap] swap concat cons - G == [direco] cons [swap] swoncat cons - -.. code:: ipython2 - - define('G == [direco] cons [swap] swoncat cons') - -Let’s try it out: - -.. code:: ipython2 - - J('0 [dup ++] G') - - -.. parsed-literal:: - - [0 swap [dup ++] direco] - - -.. code:: ipython2 - - J('0 [dup ++] G x x x pop') - - -.. parsed-literal:: - - 0 1 2 - - -Powers of 2 -~~~~~~~~~~~ - -.. code:: ipython2 - - J('1 [dup 1 <<] G x x x x x x x x x pop') - - -.. parsed-literal:: - - 1 2 4 8 16 32 64 128 256 - - -``[x] times`` -~~~~~~~~~~~~~ - -If we have one of these quoted programs we can drive it using ``times`` -with the ``x`` combinator. - -.. code:: ipython2 - - J('23 [dup ++] G 5 [x] times') - - -.. parsed-literal:: - - 23 24 25 26 27 [28 swap [dup ++] direco] - - -Generating Multiples of Three and Five --------------------------------------- - -Look at the treatment of the Project Euler Problem One in the -“Developing a Program” notebook and you’ll see that we might be -interested in generating an endless cycle of: - -:: - - 3 2 1 3 1 2 3 - -To do this we want to encode the numbers as pairs of bits in a single -int: - -:: - - 3 2 1 3 1 2 3 - 0b 11 10 01 11 01 10 11 == 14811 - -And pick them off by masking with 3 (binary 11) and then shifting the -int right two bits. - -.. code:: ipython2 - - define('PE1.1 == dup [3 &] dip 2 >>') - -.. code:: ipython2 - - V('14811 PE1.1') - - -.. parsed-literal:: - - . 14811 PE1.1 - 14811 . PE1.1 - 14811 . dup [3 &] dip 2 >> - 14811 14811 . [3 &] dip 2 >> - 14811 14811 [3 &] . dip 2 >> - 14811 . 3 & 14811 2 >> - 14811 3 . & 14811 2 >> - 3 . 14811 2 >> - 3 14811 . 2 >> - 3 14811 2 . >> - 3 3702 . - - -If we plug ``14811`` and ``[PE1.1]`` into our generator form… - -.. code:: ipython2 - - J('14811 [PE1.1] G') - - -.. parsed-literal:: - - [14811 swap [PE1.1] direco] - - -…we get a generator that works for seven cycles before it reaches zero: - -.. code:: ipython2 - - J('[14811 swap [PE1.1] direco] 7 [x] times') - - -.. parsed-literal:: - - 3 2 1 3 1 2 3 [0 swap [PE1.1] direco] - - -Reset at Zero -~~~~~~~~~~~~~ - -We need a function that checks if the int has reached zero and resets it -if so. - -.. code:: ipython2 - - define('PE1.1.check == dup [pop 14811] [] branch') - -.. code:: ipython2 - - J('14811 [PE1.1.check PE1.1] G') - - -.. parsed-literal:: - - [14811 swap [PE1.1.check PE1.1] direco] - - -.. code:: ipython2 - - J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times') - - -.. parsed-literal:: - - 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] - - -(It would be more efficient to reset the int every seven cycles but -that’s a little beyond the scope of this article. This solution does -extra work, but not much, and we’re not using it “in production” as they -say.) - -Run 466 times -~~~~~~~~~~~~~ - -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 - - J('7 66 * 4 +') - - -.. parsed-literal:: - - 466 - - -If we drive our generator 466 times and sum the stack we get 999. - -.. code:: ipython2 - - J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times') - - -.. parsed-literal:: - - 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 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 - - J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum') - - -.. parsed-literal:: - - 999 - - -Project Euler Problem One -------------------------- - -.. code:: ipython2 - - define('PE1.2 == + dup [+] dip') - -Now we can add ``PE1.2`` to the quoted program given to ``G``. - -.. code:: ipython2 - - J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop') - - -.. parsed-literal:: - - 233168 - - -A generator for the Fibonacci Sequence. ---------------------------------------- - -Consider: - -:: - - [b a F] x - [b a F] b a F - -The obvious first thing to do is just add ``b`` and ``a``: - -:: - - [b a F] b a + - [b a F] b+a - -From here we want to arrive at: - -:: - - b [b+a b F] - -Let’s start with ``swons``: - -:: - - [b a F] b+a swons - [b+a b a F] - -Considering this quote as a stack: - -:: - - F a b b+a - -We want to get it to: - -:: - - F b b+a b - -So: - -:: - - F a b b+a popdd over - F b b+a b - -And therefore: - -:: - - [b+a b a F] [popdd over] infra - [b b+a b F] - -But we can just use ``cons`` to carry ``b+a`` into the quote: - -:: - - [b a F] b+a [popdd over] cons infra - [b a F] [b+a popdd over] infra - [b b+a b F] - -Lastly: - -:: - - [b b+a b F] uncons - b [b+a b F] - -Putting it all together: - -:: - - F == + [popdd over] cons infra uncons - fib_gen == [1 1 F] - -.. code:: ipython2 - - define('fib == + [popdd over] cons infra uncons') - -.. code:: ipython2 - - define('fib_gen == [1 1 fib]') - -.. code:: ipython2 - - J('fib_gen 10 [x] times') - - -.. parsed-literal:: - - 1 2 3 5 8 13 21 34 55 89 [144 89 fib] - - -Project Euler Problem Two -------------------------- - - By considering the terms in the Fibonacci sequence whose values do - 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 -``pop``\ s it otherwise. - -.. code:: ipython2 - - define('PE2.1 == dup 2 % [+] [pop] branch') - -And a predicate function that detects when the terms in the series -“exceed four million”. - -.. code:: ipython2 - - 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. - -.. code:: ipython2 - - define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec') - -.. code:: ipython2 - - J('PE2') - - -.. parsed-literal:: - - 4613732 - - -Here’s the collected program definitions: - -:: - - fib == + swons [popdd over] infra uncons - fib_gen == [1 1 fib] - - even == dup 2 % - >4M == 4000000 > - - PE2.1 == even [+] [pop] branch - PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec - -Even-valued Fibonacci Terms -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Using ``o`` for odd and ``e`` for even: - -:: - - o + o = e - e + e = e - o + e = o - -So the Fibonacci sequence considered in terms of just parity would be: - -:: - - o o e o o e o o e o o e o o e o o e - 1 1 2 3 5 8 . . . - -Every third term is even. - -.. code:: ipython2 - - J('[1 0 fib] x x x') # To start the sequence with 1 1 2 3 instead of 1 2 3. - - -.. parsed-literal:: - - 1 1 2 [3 2 fib] - - -Drive the generator three times and ``popop`` the two odd terms. - -.. code:: ipython2 - - J('[1 0 fib] x x x [popop] dipd') - - -.. parsed-literal:: - - 2 [3 2 fib] - - -.. code:: ipython2 - - define('PE2.2 == x x x [popop] dipd') - -.. code:: ipython2 - - J('[1 0 fib] 10 [PE2.2] times') - - -.. parsed-literal:: - - 2 8 34 144 610 2584 10946 46368 196418 832040 [1346269 832040 fib] - - -Replace ``x`` with our new driver function ``PE2.2`` and start our -``fib`` generator at ``1 0``. - -.. code:: ipython2 - - J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec') - - -.. parsed-literal:: - - 4613732 - - -How to compile these? ---------------------- - -You would probably start with a special version of ``G``, and perhaps -modifications to the default ``x``? - -An Interesting Variation ------------------------- - -.. code:: ipython2 - - define('codireco == cons dip rest cons') - -.. code:: ipython2 - - V('[0 [dup ++] codireco] x') - - -.. parsed-literal:: - - . [0 [dup ++] codireco] x - [0 [dup ++] codireco] . x - [0 [dup ++] codireco] . 0 [dup ++] codireco - [0 [dup ++] codireco] 0 . [dup ++] codireco - [0 [dup ++] codireco] 0 [dup ++] . codireco - [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons - [0 [dup ++] codireco] [0 dup ++] . dip rest cons - . 0 dup ++ [0 [dup ++] codireco] rest cons - 0 . dup ++ [0 [dup ++] codireco] rest cons - 0 0 . ++ [0 [dup ++] codireco] rest cons - 0 1 . [0 [dup ++] codireco] rest cons - 0 1 [0 [dup ++] codireco] . rest cons - 0 1 [[dup ++] codireco] . cons - 0 [1 [dup ++] codireco] . - - -.. code:: ipython2 - - define('G == [codireco] cons cons') - -.. code:: ipython2 - - J('230 [dup ++] G 5 [x] times pop') - - -.. parsed-literal:: - - 230 231 232 233 234 - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Intro.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Intro.rst.txt deleted file mode 100644 index 73704cf..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Intro.rst.txt +++ /dev/null @@ -1,335 +0,0 @@ - -******************* -Thun: Joy in Python -******************* - -This implementation is meant as a tool for exploring the programming -model and method of Joy. Python seems like a great implementation -language for Joy for several reasons. - -* We can lean on the Python immutable types for our basic semantics and types: ints, floats, strings, and tuples, which enforces functional purity. -* We get garbage collection for free. -* Compilation via Cython. -* Python is a "glue language" with loads of libraries which we can wrap in Joy functions. - - -`Read-Eval-Print Loop (REPL) `__ -==================================================================================================== - -The main way to interact with the Joy interpreter is through a simple -`REPL `__ -that you start by running the package: - -:: - - $ python3 -m joy - Thun - Copyright © 2017 Simon Forman - This program comes with ABSOLUTELY NO WARRANTY; for details type "warranty". - This is free software, and you are welcome to redistribute it - under certain conditions; type "sharing" for details. - Type "words" to see a list of all words, and "[] help" to print the - docs for a word. - - - <-top - - joy? _ - -The ``<-top`` marker points to the top of the (initially empty) stack. -You can enter Joy notation at the prompt and a :doc:`trace of evaluation <../pretty>` will -be printed followed by the stack and prompt again:: - - joy? 23 sqr 18 + - - 547 <-top - - joy? - -There is a `trace` combinator:: - - joy? 23 [sqr 18 +] trace - 23 . sqr 18 + - 23 . dup mul 18 + - 23 23 . mul 18 + - 529 . 18 + - 529 18 . + - 547 . - - 547 <-top - - joy? - - -The Stack -============= - -In Joy, in addition to the types Boolean, integer, float, and string, -there is a :doc:`single sequence type <../stack>` represented by enclosing a sequence of -terms in brackets ``[...]``. This sequence type is used to represent -both the stack and the expression. It is a `cons -list `__ made from Python -tuples. - - -Purely Functional Datastructures -================================= - -Because Joy stacks are made out of Python tuples they are immutable, as are the other Python types we "borrow" for Joy, so all Joy datastructures are `purely functional `__. - - -The ``joy()`` function -======================= - -An Interpreter -~~~~~~~~~~~~~~~~~ - -The ``joy()`` interpreter function is extrememly simple. It accepts a stack, an -expression, and a dictionary, and it iterates through the expression -putting values onto the stack and delegating execution to functions which it -looks up in the dictionary. - - -`Continuation-Passing Style `__ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -One day I thought, What happens if you rewrite Joy to use -`CPS `__? I -made all the functions accept and return the expression as well as the -stack and found that all the combinators could be rewritten to work by -modifying the expression rather than making recursive calls to the -``joy()`` function. - - -View function -~~~~~~~~~~~~~ - -The ``joy()`` function accepts an optional ``viewer`` argument that -is a function which it calls on -each iteration passing the current stack and expression just before -evaluation. This can be used for tracing, breakpoints, retrying after -exceptions, or interrupting an evaluation and saving to disk or sending -over the network to resume later. The stack and expression together -contain all the state of the computation at each step. - - -The ``TracePrinter``. -~~~~~~~~~~~~~~~~~~~~~ - -A ``viewer`` records each step of the evaluation of a Joy program. The -``TracePrinter`` has a facility for printing out a trace of the -evaluation, one line per step. Each step is aligned to the current -interpreter position, signified by a period separating the stack on the -left from the pending expression ("continuation") on the right. - - -Parser -====== - -The parser is extremely simple. The undocumented ``re.Scanner`` class -does the tokenizing and then the parser builds the tuple -structure out of the tokens. There's no Abstract Syntax Tree or anything -like that. - - -Symbols -~~~~~~~~~~~~~ - -TODO: Symbols are just a string subclass; used by the parser to represent function names and by the interpreter to look up functions in the dictionary. N.B.: Symbols are not looked up at parse-time. You *could* define recursive functions, er, recusively, without ``genrec`` or other recursion combinators ``foo == ... foo ...`` but don't do that. - - -Token Regular Expressions -~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - 123 1.2 'single quotes' "double quotes" function - -TBD (look in the :module: joy.parser module.) - - -Examples -~~~~~~~~~~~ - -.. code:: python - - joy.parser.text_to_expression('1 2 3 4 5') # A simple sequence. - - -.. parsed-literal:: - - (1, (2, (3, (4, (5, ()))))) - - -.. code:: python - - joy.parser.text_to_expression('[1 2 3] 4 5') # Three items, the first is a list with three items - - -.. parsed-literal:: - - ((1, (2, (3, ()))), (4, (5, ()))) - - -.. code:: python - - 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. - - - -.. parsed-literal:: - - (1, (23, (('four', ((-5.0, ()), (cons, ()))), (8888, ())))) - - - -.. code:: python - - joy.parser.text_to_expression('[][][][][]') # Five empty lists. - - - - -.. parsed-literal:: - - ((), ((), ((), ((), ((), ()))))) - - - -.. code:: python - - joy.parser.text_to_expression('[[[[[]]]]]') # Five nested lists. - - - - -.. parsed-literal:: - - ((((((), ()), ()), ()), ()), ()) - - - -Library -======= - -The Joy library of functions (aka commands, or "words" after Forth -usage) encapsulates all the actual functionality (no pun intended) of -the Joy system. There are simple functions such as addition ``add`` (or -``+``, 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``: - -.. code:: python - - print inspect.getsource(joy.library.dip) - - -.. parsed-literal:: - - def dip(stack, expression, dictionary): - (quote, (x, stack)) = stack - expression = x, expression - return stack, concat(quote, expression), dictionary - - -Some functions are defined in equations in terms of other functions. -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:: python - - print joy.library.definitions - - -.. parsed-literal:: - - second == rest first - third == rest rest first - product == 1 swap [*] step - swons == swap cons - swoncat == swap concat - flatten == [] swap [concat] step - unit == [] cons - quoted == [unit] dip - unquoted == [i] dip - enstacken == stack [clear] dip - disenstacken == ? [uncons ?] loop pop - ? == dup truthy - dinfrirst == dip infra first - nullary == [stack] dinfrirst - unary == [stack [pop] dip] dinfrirst - binary == [stack [popop] dip] dinfrirst - ternary == [stack [popop pop] dip] dinfrirst - pam == [i] map - run == [] swap infra - sqr == dup mul - size == 0 swap [pop ++] step - cleave == [i] app2 [popd] dip - average == [sum 1.0 *] [size] cleave / - gcd == 1 [tuck modulus dup 0 >] loop pop - least_fraction == dup [gcd] infra [div] concat map - *fraction == [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons - *fraction0 == concat [[swap] dip * [*] dip] infra - down_to_zero == [0 >] [dup --] while - range_to_zero == unit [down_to_zero] infra - anamorphism == [pop []] swap [dip swons] genrec - range == [0 <=] [1 - dup] anamorphism - while == swap [nullary] cons dup dipd concat loop - dudipd == dup dipd - primrec == [i] genrec - - - -Currently, there's no function to add new definitions to the dictionary -from "within" Joy code itself. Adding new definitions remains a -meta-interpreter action. You have to do it yourself, in Python, and wash -your hands afterward. - -It would be simple enough to define one, but it would open the door to -*name binding* and break the idea that all state is captured in the -stack and expression. There's an implicit *standard dictionary* that -defines the actual semantics of the syntactic stack and expression -datastructures (which only contain symbols, not the actual functions. -Pickle some and see for yourself.) - -"There should be only one." -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Which brings me to talking about one of my hopes and dreams for this -notation: "There should be only one." What I mean is that there should -be one universal standard dictionary of commands, and all bespoke work -done in a UI for purposes takes place by direct interaction and macros. -There would be a *Grand Refactoring* biannually (two years, not six -months, that's semi-annually) where any new definitions factored out of -the usage and macros of the previous time, along with new algorithms and -such, were entered into the dictionary and posted to e.g. IPFS. - -Code should not burgeon wildly, as it does today. The variety of code -should map more-or-less to the well-factored variety of human -computably-solvable problems. There shouldn't be dozens of chat apps, JS -frameworks, programming languages. It's a waste of time, a `fractal -"thundering herd" -attack `__ on -human mentality. - -Literary Code Library -~~~~~~~~~~~~~~~~~~~~~ - -If you read over the other notebooks you'll see that developing code in -Joy is a lot like doing simple mathematics, and the descriptions of the -code resemble math papers. The code also works the first time, no bugs. -If you have any experience programming at all, you are probably -skeptical, as I was, but it seems to work: deriving code mathematically -seems to lead to fewer errors. - -But my point now is that this great ratio of textual explanation to wind -up with code that consists of a few equations and could fit on an index -card is highly desirable. Less code has fewer errors. The structure of -Joy engenders a kind of thinking that seems to be very effective for -developing structured processes. - -There seems to be an elegance and power to the notation. - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Newton-Raphson.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Newton-Raphson.rst.txt deleted file mode 100644 index cb3f759..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Newton-Raphson.rst.txt +++ /dev/null @@ -1,257 +0,0 @@ -`Newton's method `__ -===================================================================== - -Let's use the Newton-Raphson method for finding the root of an equation -to write a function that can compute the square root of a number. - -Cf. `"Why Functional Programming Matters" by John -Hughes `__ - -.. code:: ipython3 - - from notebook_preamble import J, V, define - -A Generator for Approximations ------------------------------- - -To make a generator that generates successive approximations let’s start -by assuming an initial approximation and then derive the function that -computes the next approximation: - -:: - - a F - --------- - a' - -A Function to Compute the Next Approximation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This is the equation for computing the next approximate value of the -square root: - -:math:`a_{i+1} = \frac{(a_i+\frac{n}{a_i})}{2}` - -:: - - a n over / + 2 / - a n a / + 2 / - a n/a + 2 / - a+n/a 2 / - (a+n/a)/2 - -The function we want has the argument ``n`` in it: - -:: - - F == n over / + 2 / - -Make it into a Generator -~~~~~~~~~~~~~~~~~~~~~~~~ - -Our generator would be created by: - -:: - - a [dup F] make_generator - -With n as part of the function F, but n is the input to the sqrt -function we’re writing. If we let 1 be the initial approximation: - -:: - - 1 n 1 / + 2 / - 1 n/1 + 2 / - 1 n + 2 / - n+1 2 / - (n+1)/2 - -The generator can be written as: - -:: - - 23 1 swap [over / + 2 /] cons [dup] swoncat make_generator - 1 23 [over / + 2 /] cons [dup] swoncat make_generator - 1 [23 over / + 2 /] [dup] swoncat make_generator - 1 [dup 23 over / + 2 /] make_generator - -.. code:: ipython3 - - define('gsra 1 swap [over / + 2 /] cons [dup] swoncat make_generator') - -.. code:: ipython3 - - J('23 gsra') - - -.. parsed-literal:: - - [1 [dup 23 over / + 2 /] codireco] - - -Let's drive the generator a few time (with the ``x`` combinator) and -square the approximation to see how well it works... - -.. code:: ipython3 - - J('23 gsra 6 [x popd] times first sqr') - - -.. parsed-literal:: - - 23.0000000001585 - - -Finding Consecutive Approximations within a Tolerance ------------------------------------------------------ - -From `"Why Functional Programming Matters" by John -Hughes `__: - - The remainder of a square root finder is a function *within*, which - takes a tolerance and a list of approximations and looks down the - list for two successive approximations that differ by no more than - the given tolerance. - -(And note that by “list” he means a lazily-evaluated list.) - -Using the *output* ``[a G]`` of the above generator for square root -approximations, and further assuming that the first term a has been -generated already and epsilon ε is handy on the stack... - -:: - - a [b G] ε within - ---------------------- a b - abs ε <= - b - - - a [b G] ε within - ---------------------- a b - abs ε > - b [c G] ε within - -Predicate -~~~~~~~~~ - -:: - - a [b G] ε [first - abs] dip <= - a [b G] first - abs ε <= - a b - abs ε <= - a-b abs ε <= - abs(a-b) ε <= - (abs(a-b)<=ε) - -.. code:: ipython3 - - define('_within_P [first - abs] dip <=') - -Base-Case -~~~~~~~~~ - -:: - - a [b G] ε roll< popop first - [b G] ε a popop first - [b G] first - b - -.. code:: ipython3 - - define('_within_B roll< popop first') - -Recur -~~~~~ - -:: - - a [b G] ε R0 [within] R1 - -1. Discard a. -2. Use ``x`` combinator to generate next term from ``G``. -3. Run ``within`` with ``i`` (it is a "tail-recursive" function.) - -Pretty straightforward: - -:: - - a [b G] ε R0 [within] R1 - a [b G] ε [popd x] dip [within] i - a [b G] popd x ε [within] i - [b G] x ε [within] i - b [c G] ε [within] i - b [c G] ε within - - b [c G] ε within - -.. code:: ipython3 - - define('_within_R [popd x] dip') - -Setting up -~~~~~~~~~~ - -The recursive function we have defined so far needs a slight preamble: -``x`` to prime the generator and the epsilon value to use: - -:: - - [a G] x ε ... - a [b G] ε ... - -.. code:: ipython3 - - define('within x 0.000000001 [_within_P] [_within_B] [_within_R] tailrec') - define('sqrt gsra within') - -Try it out... - -.. code:: ipython3 - - J('36 sqrt') - - -.. parsed-literal:: - - 6.0 - - -.. code:: ipython3 - - J('23 sqrt') - - -.. parsed-literal:: - - 4.795831523312719 - - -Check it. - -.. code:: ipython3 - - 4.795831523312719**2 - - - - -.. parsed-literal:: - - 22.999999999999996 - - - -.. code:: ipython3 - - from math import sqrt - - sqrt(23) - - - - -.. parsed-literal:: - - 4.795831523312719 - - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/NoUpdates.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/NoUpdates.rst.txt deleted file mode 100644 index f58bc8f..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/NoUpdates.rst.txt +++ /dev/null @@ -1,22 +0,0 @@ - -************** -No Updates -************** - -DRAFT - -1. Joy doesn't need to change. - - A. The interpreter doesn't need to change, ``viewer`` function can customize mainloop. Or use a sub-interpreter (Joy in Joy.) The base interpreter remains static. - B. Once a function has been named and defined *never change that name*. It's just not allowed. If you need to change a function ``foo`` you have to call it ``foo_II`` or something. Once a function (name mapped to behavior) is released to the public *that's it*, it's done. - C. The language evolves by adding new definitions and refactoring, always choosing new names for new functions. - -2. Following `Semantic Versioning`_ there will never be a version 2.0. - - A. `Major version must be incremented if any backwards incompatible changes are introduced to the public API. `__ - B. We never implement any backwards incompatible changes, so... - C. We could see e.g. Thun version 1.273.3! - - -.. _Semantic Versioning: https://semver.org - 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 deleted file mode 100644 index 569d665..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Ordered_Binary_Trees.rst.txt +++ /dev/null @@ -1,1639 +0,0 @@ -Treating Trees I: Ordered Binary Trees -====================================== - -Although any expression in Joy can be considered to describe a -`tree `__ with the quotes -as compound nodes and the non-quote values as leaf nodes, in this page I -want to talk about `ordered binary -trees `__ and how to -make and use them. - -The basic structure, in a `crude type -notation `__, is: - -:: - - Tree :: [] | [key value Tree Tree] - -That says that a Tree is either the empty quote ``[]`` or a quote with -four items: a key, a value, and two Trees representing the left and -right branches of the tree. - -We’re going to derive some recursive functions to work with such -datastructures: - -:: - - Tree-add - Tree-delete - Tree-get - Tree-iter - Tree-iter-order - -Once these functions are defined we have a new “type” to work with, and -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.) - -.. code:: ipython2 - - from notebook_preamble import D, J, V, define, DefinitionWrapper - -Adding Nodes to the Tree ------------------------- - -Let’s consider adding nodes to a Tree structure. - -:: - - Tree value key Tree-add - ----------------------------- - Tree′ - -Adding to an empty node. -~~~~~~~~~~~~~~~~~~~~~~~~ - -If the current node is ``[]`` then you just return -``[key value [] []]``: - -:: - - Tree-add == [popop not] [[pop] dipd Tree-new] [R0] [R1] genrec - -``Tree-new`` -^^^^^^^^^^^^ - -Where ``Tree-new`` is defined as: - -:: - - value key Tree-new - ------------------------ - [key value [] []] - -Example: - -:: - - value key swap [[] []] cons cons - key value [[] []] cons cons - key [value [] []] cons - [key value [] []] - -Definition: - -:: - - Tree-new == swap [[] []] cons cons - -.. code:: ipython2 - - define('Tree-new == swap [[] []] cons cons') - -.. code:: ipython2 - - J('"v" "k" Tree-new') - - -.. parsed-literal:: - - ['k' 'v' [] []] - - -(As an implementation detail, the ``[[] []]`` literal used in the -definition of ``Tree-new`` will be reused to supply the *constant* tail -for *all* new nodes produced by it. This is one of those cases where you -get amortized storage “for free” by using `persistent -datastructures `__. -Because the tail, which is ``((), ((), ()))`` in Python, is immutable -and embedded in the definition body for ``Tree-new``, all new nodes can -reuse it as their own tail without fear that some other code somewhere -will change it.) - -Adding to a non-empty node. -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We now have to derive ``R0`` and ``R1``, consider: - -:: - - [key_n value_n left right] value key R0 [Tree-add] R1 - -In this case, there are three possibilites: the key can be greater or -less than or equal to the node’s key. In two of those cases we will need -to apply a copy of ``Tree-add``, so ``R0`` is pretty much out of the -picture. - -:: - - [R0] == [] - -A predicate to compare keys. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - [key_n value_n left right] value key [BTree-add] R1 - -The first thing we need to do is compare the the key we’re adding to the -node key and ``branch`` accordingly: - -:: - - [key_n value_n left right] value key [BTree-add] [P] [T] [E] ifte - -That would suggest something like: - -:: - - [key_n value_n left right] value key [BTree-add] P - [key_n value_n left right] value key [BTree-add] pop roll> pop first > - [key_n value_n left right] value key roll> pop first > - key [key_n value_n left right] value roll> pop first > - key key_n > - Boolean - -Let’s abstract the predicate just a little to let us specify the -comparison operator: - -:: - - P > == pop roll> pop first > - P < == pop roll> pop first < - P == pop roll> pop first - -.. code:: ipython2 - - define('P == pop roll> pop first') - -.. code:: ipython2 - - J('["old_key" 23 [] []] 17 "new_key" ["..."] P') - - -.. parsed-literal:: - - 'new_key' 'old_key' - - -If the key we’re adding is greater than the node’s key. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Here the parentheses are meant to signify that the expression is not -literal, the code in the parentheses is meant to have been evaluated: - -:: - - [key_n value_n left right] value key [Tree-add] T - ------------------------------------------------------- - [key_n value_n left (Tree-add key value right)] - -So how do we do this? We’re going to want to use ``infra`` on some -function ``K`` that has the key and value to work with, as well as the -quoted copy of ``Tree-add`` to apply somehow. Considering the node as a -stack: - -:: - - right left value_n key_n value key [Tree-add] K - ----------------------------------------------------- - right value key Tree-add left value_n key_n - -Pretty easy: - -:: - - right left value_n key_n value key [Tree-add] cons cons dipdd - right left value_n key_n [value key Tree-add] dipdd - right value key Tree-add left value_n key_n - -So: - -:: - - K == cons cons dipdd - -Looking at it from the point-of-view of the node as node again: - -:: - - [key_n value_n left right] [value key [Tree-add] K] infra - -Expand ``K`` and evaluate a little: - -:: - - [key_n value_n left right] [value key [Tree-add] K] infra - [key_n value_n left right] [value key [Tree-add] cons cons dipdd] infra - [key_n value_n left right] [[value key Tree-add] dipdd] infra - -Then, working backwards: - -:: - - [key_n value_n left right] [[value key Tree-add] dipdd] infra - [key_n value_n left right] [value key Tree-add] [dipdd] cons infra - [key_n value_n left right] value key [Tree-add] cons cons [dipdd] cons infra - -And so ``T`` is just: - -:: - - T == cons cons [dipdd] cons infra - -.. code:: ipython2 - - define('T == cons cons [dipdd] cons infra') - -.. code:: ipython2 - - J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T') - - -.. parsed-literal:: - - ['old_k' 'old_value' 'left' 'Tree-add' 'new_key' 'new_value' 'right'] - - -If the key we’re adding is less than the node’s key. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -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 - - define('E == [P <] [Te] [Ee] ifte') - -In this case ``Te`` works that same as ``T`` but on the left child tree -instead of the right, so the only difference is that it must use -``dipd`` instead of ``dipdd``: - -:: - - Te == cons cons [dipd] cons infra - -.. code:: ipython2 - - define('Te == cons cons [dipd] cons infra') - -.. code:: ipython2 - - J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te') - - -.. parsed-literal:: - - ['old_k' 'old_value' 'Tree-add' 'new_key' 'new_value' 'left' 'right'] - - -Else the keys must be equal. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This means we must find: - -:: - - [key old_value left right] new_value key [Tree-add] Ee - ------------------------------------------------------------ - [key new_value left right] - -This is another easy one: - -:: - - Ee == pop swap roll< rest rest cons cons - -Example: - -:: - - [key old_value left right] new_value key [Tree-add] pop swap roll< rest rest cons cons - [key old_value left right] new_value key swap roll< rest rest cons cons - [key old_value left right] key new_value roll< rest rest cons cons - key new_value [key old_value left right] rest rest cons cons - key new_value [ left right] cons cons - [key new_value left right] - -.. code:: ipython2 - - define('Ee == pop swap roll< rest rest cons cons') - -.. code:: ipython2 - - J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee') - - -.. parsed-literal:: - - ['k' 'new_value' 'left' 'right'] - - -Now we can define ``Tree-add`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec - -Putting it all together: - -:: - - Tree-new == swap [[] []] cons cons - P == pop roll> pop first - T == cons cons [dipdd] cons infra - Te == cons cons [dipd] cons infra - Ee == pop swap roll< rest rest cons cons - E == [P <] [Te] [Ee] ifte - R == [P >] [T] [E] ifte - - Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec - -.. code:: ipython2 - - define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec') - -Examples -~~~~~~~~ - -.. code:: ipython2 - - J('[] 23 "b" Tree-add') # Initial - - -.. parsed-literal:: - - ['b' 23 [] []] - - -.. code:: ipython2 - - J('["b" 23 [] []] 88 "c" Tree-add') # Greater than - - -.. parsed-literal:: - - ['b' 23 [] ['c' 88 [] []]] - - -.. code:: ipython2 - - J('["b" 23 [] []] 88 "a" Tree-add') # Less than - - -.. parsed-literal:: - - ['b' 23 ['a' 88 [] []] []] - - -.. code:: ipython2 - - J('["b" 23 [] []] 88 "b" Tree-add') # Equal to - - -.. parsed-literal:: - - ['b' 88 [] []] - - -.. code:: ipython2 - - J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Series. - - -.. parsed-literal:: - - ['b' 23 ['a' 88 [] []] ['c' 44 [] []]] - - -.. code:: ipython2 - - J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step') - - -.. parsed-literal:: - - ['b' 23 ['a' 88 [] []] ['c' 44 [] []]] - - -Interlude: ``cmp`` combinator ------------------------------ - -Instead of mucking about with nested ``ifte`` combinators let’s use -``cmp`` which takes two values and three quoted programs on the stack -and runs one of the three depending on the results of comparing the two -values: - -:: - - a b [G] [E] [L] cmp - ------------------------- a > b - G - - a b [G] [E] [L] cmp - ------------------------- a = b - E - - a b [G] [E] [L] cmp - ------------------------- a < b - L - -.. code:: ipython2 - - J("1 0 ['G'] ['E'] ['L'] cmp") - - -.. parsed-literal:: - - 'G' - - -.. code:: ipython2 - - J("1 1 ['G'] ['E'] ['L'] cmp") - - -.. parsed-literal:: - - 'E' - - -.. code:: ipython2 - - J("0 1 ['G'] ['E'] ['L'] cmp") - - -.. parsed-literal:: - - 'L' - - -Redefine ``Tree-add`` -~~~~~~~~~~~~~~~~~~~~~ - -We need a new non-destructive predicate ``P``: - -:: - - [node_key node_value left right] value key [Tree-add] P - ------------------------------------------------------------------------ - [node_key node_value left right] value key [Tree-add] key node_key - -Let’s start with ``over`` to get a copy of the key and then apply some -function ``Q`` with the ``nullary`` combinator so it can dig out the -node key (by throwing everything else away): - -:: - - P == over [Q] nullary - - [node_key node_value left right] value key [Tree-add] over [Q] nullary - [node_key node_value left right] value key [Tree-add] key [Q] nullary - -And ``Q`` would be: - -:: - - Q == popop popop first - - [node_key node_value left right] value key [Tree-add] key Q - [node_key node_value left right] value key [Tree-add] key popop popop first - [node_key node_value left right] value key popop first - [node_key node_value left right] first - node_key - -Or just: - -:: - - P == over [popop popop first] nullary - -.. code:: ipython2 - - define('P == over [popop popop first] nullary') - -Using ``cmp`` to simplify `our code above at -``R1`` <#Adding-to-a-non-empty-node.>`__: - -:: - - [node_key node_value left right] value key [Tree-add] R1 - [node_key node_value left right] value key [Tree-add] P [T] [E] [Te] cmp - -The line above becomes one of the three lines below: - -:: - - [node_key node_value left right] value key [Tree-add] T - [node_key node_value left right] value key [Tree-add] E - [node_key node_value left right] value key [Tree-add] Te - -The definition is a little longer but, I think, more elegant and easier -to understand: - -:: - - Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec - -.. code:: ipython2 - - define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec') - -.. code:: ipython2 - - J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Still works. - - -.. parsed-literal:: - - ['b' 23 ['a' 88 [] []] ['c' 44 [] []]] - - -A Function to Traverse this Structure -------------------------------------- - -Let’s take a crack at writing a function that can recursively iterate or -traverse these trees. - -Base case ``[]`` -~~~~~~~~~~~~~~~~ - -The stopping predicate just has to detect the empty list: - -:: - - Tree-iter == [not] [E] [R0] [R1] genrec - -And since there’s nothing at this node, we just ``pop`` it: - -:: - - Tree-iter == [not] [pop] [R0] [R1] genrec - -Node case ``[key value left right]`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now we need to figure out ``R0`` and ``R1``: - -:: - - Tree-iter == [not] [pop] [R0] [R1] genrec - == [not] [pop] [R0 [Tree-iter] R1] ifte - -Let’s look at it *in situ*: - -:: - - [key value left right] R0 [Tree-iter] R1 - -Processing the current node. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -``R0`` is almost certainly going to use ``dup`` to make a copy of the -node and then ``dip`` on some function to process the copy with it: - -:: - - [key value left right] [F] dupdip [Tree-iter] R1 - [key value left right] F [key value left right] [Tree-iter] R1 - -For example, if we’re getting all the keys ``F`` would be ``first``: - -:: - - R0 == [first] dupdip - - [key value left right] [first] dupdip [Tree-iter] R1 - [key value left right] first [key value left right] [Tree-iter] R1 - key [key value left right] [Tree-iter] R1 - -Recur -^^^^^ - -Now ``R1`` needs to apply ``[Tree-iter]`` to ``left`` and ``right``. If -we drop the key and value from the node using ``rest`` twice we are left -with an interesting situation: - -:: - - key [key value left right] [Tree-iter] R1 - key [key value left right] [Tree-iter] [rest rest] dip - key [key value left right] rest rest [Tree-iter] - key [left right] [Tree-iter] - -Hmm, will ``step`` do? - -:: - - key [left right] [Tree-iter] step - key left Tree-iter [right] [Tree-iter] step - key left-keys [right] [Tree-iter] step - key left-keys right Tree-iter - key left-keys right-keys - -Neat. So: - -:: - - R1 == [rest rest] dip step - -Putting it together -~~~~~~~~~~~~~~~~~~~ - -We have: - -:: - - Tree-iter == [not] [pop] [[F] dupdip] [[rest rest] dip step] genrec - -When I was reading this over I realized ``rest rest`` could go in -``R0``: - -:: - - Tree-iter == [not] [pop] [[F] dupdip rest rest] [step] genrec - -(And ``[step] genrec`` is such a cool and suggestive combinator!) - -Parameterizing the ``F`` per-node processing function. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - [F] Tree-iter - ------------------------------------------------------ - [not] [pop] [[F] dupdip rest rest] [step] genrec - -Working backward: - -:: - - [not] [pop] [[F] dupdip rest rest] [step] genrec - [not] [pop] [F] [dupdip rest rest] cons [step] genrec - [F] [not] [pop] roll< [dupdip rest rest] cons [step] genrec - -``Tree-iter`` -~~~~~~~~~~~~~ - -:: - - Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec - -.. code:: ipython2 - - define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec') - -Examples -~~~~~~~~ - -.. code:: ipython2 - - J('[] [foo] Tree-iter') # It doesn't matter what F is as it won't be used. - - -.. parsed-literal:: - - - - -.. code:: ipython2 - - J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter") - - -.. parsed-literal:: - - 'b' 'a' 'c' - - -.. code:: ipython2 - - J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter") - - -.. parsed-literal:: - - 23 88 44 - - -Interlude: A Set-like Datastructure ------------------------------------ - -We can use this to make a set-like datastructure by just setting values -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)` `__ -time. - -.. code:: ipython2 - - J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step') - - -.. parsed-literal:: - - [3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]] - - -.. code:: ipython2 - - define('to_set == [] swap [0 swap Tree-add] step') - -.. code:: ipython2 - - J('[3 9 5 2 8 6 7 8 4] to_set') - - -.. parsed-literal:: - - [3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]] - - -And with that we can write a little program ``unique`` to remove -duplicate items from a list. - -.. code:: ipython2 - - define('unique == [to_set [first] Tree-iter] cons run') - -.. code:: ipython2 - - J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique') # Filter duplicate items. - - -.. parsed-literal:: - - [7 6 8 4 5 9 2 3] - - -A Version of ``Tree-iter`` that does In-Order Traversal -------------------------------------------------------- - -If you look back to the `non-empty case of the ``Tree-iter`` -function <#Node-case-%5Bkey-value-left-right%5D>`__ we can design a -variant that first processes the left child, then the current node, then -the right child. This will allow us to traverse the tree in sort order. - -:: - - Tree-iter-order == [not] [pop] [R0] [R1] genrec - -To define ``R0`` and ``R1`` it helps to look at them as they will appear -when they run: - -:: - - [key value left right] R0 [BTree-iter-order] R1 - -Process the left child. -~~~~~~~~~~~~~~~~~~~~~~~ - -Staring at this for a bit suggests ``dup third`` to start: - -:: - - [key value left right] R0 [Tree-iter-order] R1 - [key value left right] dup third [Tree-iter-order] R1 - [key value left right] left [Tree-iter-order] R1 - -Now maybe: - -:: - - [key value left right] left [Tree-iter-order] [cons dip] dupdip - [key value left right] left [Tree-iter-order] cons dip [Tree-iter-order] - [key value left right] [left Tree-iter-order] dip [Tree-iter-order] - left Tree-iter-order [key value left right] [Tree-iter-order] - -Process the current node. -~~~~~~~~~~~~~~~~~~~~~~~~~ - -So far, so good. Now we need to process the current node’s values: - -:: - - left Tree-iter-order [key value left right] [Tree-iter-order] [[F] dupdip] dip - left Tree-iter-order [key value left right] [F] dupdip [Tree-iter-order] - left Tree-iter-order [key value left right] F [key value left right] [Tree-iter-order] - -If ``F`` needs items from the stack below the left stuff it should have -``cons``\ ’d them before beginning maybe? For functions like ``first`` -it works fine as-is. - -:: - - left Tree-iter-order [key value left right] first [key value left right] [Tree-iter-order] - left Tree-iter-order key [key value left right] [Tree-iter-order] - -Process the right child. -~~~~~~~~~~~~~~~~~~~~~~~~ - -First ditch the rest of the node and get the right child: - -:: - - left Tree-iter-order key [key value left right] [Tree-iter-order] [rest rest rest first] dip - left Tree-iter-order key right [Tree-iter-order] - -Then, of course, we just need ``i`` to run ``Tree-iter-order`` on the -right side: - -:: - - left Tree-iter-order key right [Tree-iter-order] i - left Tree-iter-order key right Tree-iter-order - -Defining ``Tree-iter-order`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The result is a little awkward: - -:: - - R1 == [cons dip] dupdip [[F] dupdip] dip [rest rest rest first] dip i - -Let’s do a little semantic factoring: - -:: - - fourth == rest rest rest first - - proc_left == [cons dip] dupdip - proc_current == [[F] dupdip] dip - proc_right == [fourth] dip i - - Tree-iter-order == [not] [pop] [dup third] [proc_left proc_current proc_right] genrec - -Now we can sort sequences. - -.. code:: ipython2 - - #define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec') - - - DefinitionWrapper.add_definitions(''' - - fourth == rest rest rest first - - 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 - - ''', D) - - - - -.. code:: ipython2 - - J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order') - - -.. parsed-literal:: - - 2 3 4 5 6 7 8 9 - - -Parameterizing the ``[F]`` function is left as an exercise for the -reader. - -Getting values by key ---------------------- - -Let’s derive a function that accepts a tree and a key and returns the -value associated with that key. - -:: - - tree key Tree-get - ----------------------- - value - -But what do we do if the key isn’t in the tree? In Python we might raise -a ``KeyError`` but I’d like to avoid exceptions in Joy if possible, and -here I think it’s possible. (Division by zero is an example of where I -think it’s probably better to let Python crash Joy. Sometimes the -machinery fails and you have to “stop the line”, I think.) - -Let’s pass the buck to the caller by making the base case a given, you -have to decide for yourself what ``[E]`` should be. - -:: - - tree key [E] Tree-get - ---------------------------- key in tree - value - - tree key [E] Tree-get - ---------------------------- key not in tree - [] key E - -The base case ``[]`` -~~~~~~~~~~~~~~~~~~~~ - -As before, the stopping predicate just has to detect the empty list: - -:: - - Tree-get == [pop not] [E] [R0] [R1] genrec - -So we define: - -:: - - Tree-get == [pop not] swap [R0] [R1] genrec - -Note that this ``Tree-get`` creates a slightly different function than -itself and *that function* does the actual recursion. This kind of -higher-level programming is unusual in most languages but natural in -Joy. - -:: - - tree key [E] [pop not] swap [R0] [R1] genrec - tree key [pop not] [E] [R0] [R1] genrec - -The anonymous specialized recursive function that will do the real work. - -:: - - [pop not] [E] [R0] [R1] genrec - -Node case ``[key value left right]`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now we need to figure out ``R0`` and ``R1``: - -:: - - [key value left right] key R0 [BTree-get] R1 - -We want to compare the search key with the key in the node, and if they -are the same return the value, otherwise recur on one of the child -nodes. So it’s very similar to the above funtion, with ``[R0] == []`` -and ``R1 == P [T>] [E] [T<] cmp``: - -:: - - [key value left right] key [BTree-get] P [T>] [E] [T<] cmp - -Predicate -^^^^^^^^^ - -:: - - P == over [get-node-key] nullary - get-node-key == pop popop first - -The only difference is that ``get-node-key`` does one less ``pop`` -because there’s no value to discard. - -Branches -^^^^^^^^ - -Now we have to derive the branches: - -:: - - [key_n value_n left right] key [BTree-get] T> - [key_n value_n left right] key [BTree-get] E - [key_n value_n left right] key [BTree-get] T< - -Greater than and less than -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The cases of ``T>`` and ``T<`` are similar to above but instead of using -``infra`` we have to discard the rest of the structure: - -:: - - [key_n value_n left right] key [BTree-get] T> - --------------------------------------------------- - right key BTree-get - -And: - -:: - - [key_n value_n left right] key [BTree-get] T< - --------------------------------------------------- - left key BTree-get - -So: - -:: - - T> == [fourth] dipd i - T< == [third] dipd i - -E.g.: - -:: - - [key_n value_n left right] key [BTree-get] [fourth] dipd i - [key_n value_n left right] fourth key [BTree-get] i - right key [BTree-get] i - right key BTree-get - -Equal keys -^^^^^^^^^^ - -Return the node’s value: - -:: - - [key_n value_n left right] key [BTree-get] E == value_n - - E == popop second - -``Tree-get`` -~~~~~~~~~~~~ - -So: - -:: - - fourth == rest rest rest first - get-node-key == pop popop first - P == over [get-node-key] nullary - T> == [fourth] dipd i - T< == [third] dipd i - E == popop second - - Tree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec - -.. code:: ipython2 - - # I don't want to deal with name conflicts with the above so I'm inlining everything here. - # The original Joy system has "hide" which is a meta-command which allows you to use named - # 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 - ''') - -.. code:: ipython2 - - J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get') - - -.. parsed-literal:: - - 'mike not in tree' - - -.. code:: ipython2 - - J('["gary" 23 [] []] "gary" [popop "err"] Tree-get') - - -.. parsed-literal:: - - 23 - - -.. code:: ipython2 - - J(''' - - [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step - - 'c' [popop 'not found'] Tree-get - - ''') - - -.. parsed-literal:: - - 2 - - -.. code:: ipython2 - - J(''' - - [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step - - 'd' [popop 'not found'] Tree-get - - ''') - - -.. parsed-literal:: - - 'not found' - - -Tree-delete ------------ - -Now let’s write a function that can return a tree datastructure with a -key, value pair deleted: - -:: - - tree key Tree-delete - --------------------------- - tree - -If the key is not in tree it just returns the tree unchanged. - -Base case -~~~~~~~~~ - -Same as above. - -:: - - Tree-Delete == [pop not] [pop] [R0] [R1] genrec - -Recur -~~~~~ - -Now we get to figure out the recursive case. We need the node’s key to -compare and we need to carry the key into recursive branches. Let ``D`` -be shorthand for ``Tree-Delete``: - -:: - - D == Tree-Delete == [pop not] [pop] [R0] [R1] genrec - - [node_key node_value left right] key R0 [D] R1 - [node_key node_value left right] key over first swap dup [D] cons R1′ - [node_key node_value left right] key [...] first swap dup [D] cons R1′ - [node_key node_value left right] key node_key swap dup [D] cons R1′ - [node_key node_value left right] node_key key dup [D] cons R1′ - [node_key node_value left right] node_key key key [D] cons R1′ - [node_key node_value left right] node_key key [key D] R1′ - -And then: - -:: - - [node_key node_value left right] node_key key [key D] R1′ - [node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp - [node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp - [node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp - -So: - -:: - - R0 == over first swap dup - R1 == cons roll> [T>] [E] [T<] cmp - -Compare Keys -~~~~~~~~~~~~ - -The last line above: - -:: - - [node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp - -Then becomes one of these three: - -:: - - [node_key node_value left right] [key D] T> - [node_key node_value left right] [key D] E - [node_key node_value left right] [key D] T< - -Greater than case and less than case -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - [node_key node_value left right] [F] T> - ------------------------------------------------- - [node_key node_value (left F) right] - - - [node_key node_value left right] [F] T< - ------------------------------------------------- - [node_key node_value left (right F)] - -First, treating the node as a stack: - -:: - - right left node_value node_key [key D] dipd - right left key D node_value node_key - right left' node_value node_key - -Ergo: - -:: - - [node_key node_value left right] [key D] [dipd] cons infra - -So: - -:: - - T> == [dipd] cons infra - T< == [dipdd] cons infra - -The else case -~~~~~~~~~~~~~ - -We have found the node in the tree where ``key`` equals ``node_key``. We -need to replace the current node with something - -:: - - [node_key node_value left right] [key D] E - ------------------------------------------------ - tree - -We have to handle three cases, so let’s use ``cond``. - -One or more child nodes are ``[]`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The first two cases are symmetrical: if we only have one non-empty child -node return it. If both child nodes are empty return an empty node. - -:: - - E == [ - [[pop third not] pop fourth] - [[pop fourth not] pop third] - [default] - ] cond - -Both child nodes are non-empty. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If both child nodes are non-empty, we find the highest node in our lower -sub-tree, take its key and value to replace (delete) our own, then get -rid of it by recursively calling delete() on our lower sub-node with our -new key. - -(We could also find the lowest node in our higher sub-tree and take its -key and value and delete it. I only implemented one of these two -symmetrical options. Over a lot of deletions this might make the tree -more unbalanced. Oh well.) - -The initial structure of the default function: - -:: - - default == [E′] cons infra - - [node_key node_value left right] [key D] default - [node_key node_value left right] [key D] [E′] cons infra - [node_key node_value left right] [[key D] E′] infra - - right left node_value node_key [key D] E′ - -First things first, we no longer need this node’s key and value: - -:: - - right left node_value node_key [key D] roll> popop E″ - right left [key D] node_value node_key popop E″ - right left [key D] E″ - -We have to we find the highest (right-most) node in our lower (left) sub-tree: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - right left [key D] E″ - -Ditch the key: - -:: - - right left [key D] rest E‴ - right left [D] E‴ - -Find the right-most node: - -:: - - right left [D] [dup W] dip E⁗ - right left dup W [D] E⁗ - right left left W [D] E⁗ - -Consider: - -:: - - left W - -We know left is not empty: - -:: - - [L_key L_value L_left L_right] W - -We want to keep extracting the right node as long as it is not empty: - -:: - - W.rightmost == [P] [B] while - - left W.rightmost W′ - -The predicate: - -:: - - [L_key L_value L_left L_right] P - [L_key L_value L_left L_right] fourth - L_right - -This can run on ``[]`` so must be guarded: - -:: - - ?fourth == [] [fourth] [] ifte - -( if_not_empty == [] swap [] ifte ?fourth == [fourth] if_not_empty ) - -The body is just ``fourth``: - -:: - - left [?fourth] [fourth] while W′ - rightest W′ - -So: - -:: - - W.rightmost == [?fourth] [fourth] while - -Found right-most node in our left sub-tree -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -We know rightest is not empty: - -:: - - [R_key R_value R_left R_right] W′ - [R_key R_value R_left R_right] W′ - [R_key R_value R_left R_right] uncons uncons pop - R_key [R_value R_left R_right] uncons pop - R_key R_value [R_left R_right] pop - R_key R_value - -So: - -:: - - W == [?fourth] [fourth] while uncons uncons pop - -And: - -:: - - right left left W [D] E⁗ - right left R_key R_value [D] E⁗ - -Replace current node key and value, recursively delete rightmost -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Final stretch. We want to end up with something like: - -:: - - right left [R_key D] i R_value R_key - right left R_key D R_value R_key - right left′ R_value R_key - -If we adjust our definition of ``W`` to include ``over`` at the end: - -:: - - W == [fourth] [fourth] while uncons uncons pop over - -That will give us: - -:: - - right left R_key R_value R_key [D] E⁗ - - right left R_key R_value R_key [D] cons dipd E⁗′ - right left R_key R_value [R_key D] dipd E⁗′ - right left R_key D R_key R_value E⁗′ - right left′ R_key R_value E⁗′ - right left′ R_key R_value swap - right left′ R_value R_key - -So: - -:: - - E′ == roll> popop E″ - - E″ == rest E‴ - - E‴ == [dup W] dip E⁗ - - E⁗ == cons dipdd swap - -Substituting: - -:: - - W == [fourth] [fourth] while uncons uncons pop over - E′ == roll> popop rest [dup W] dip cons dipd swap - E == [ - [[pop third not] pop fourth] - [[pop fourth not] pop third] - [[E′] cons infra] - ] cond - -Minor rearrangement, move ``dup`` into ``W``: - -:: - - W == dup [fourth] [fourth] while uncons uncons pop over - E′ == roll> popop rest [W] dip cons dipd swap - E == [ - [[pop third not] pop fourth] - [[pop fourth not] pop third] - [[E′] cons infra] - ] cond - -Refactoring -~~~~~~~~~~~ - -:: - - W.rightmost == [fourth] [fourth] while - W.unpack == uncons uncons pop - W == dup W.rightmost W.unpack over - E.clear_stuff == roll> popop rest - E.delete == cons dipd - 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 - BTree-Delete == [pop not] swap [R0] [R1] genrec - -By the standards of the code I’ve written so far, this is a *huge* Joy -program. - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ") - - -.. parsed-literal:: - - ['a' 23 [] ['b' 88 [] []]] - - -.. code:: ipython2 - - J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ") - - -.. parsed-literal:: - - ['a' 23 [] ['c' 44 [] []]] - - -.. code:: ipython2 - - J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ") - - -.. parsed-literal:: - - ['b' 88 [] ['c' 44 [] []]] - - -.. code:: ipython2 - - J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ") - - -.. parsed-literal:: - - ['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] - - -.. code:: ipython2 - - J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step') - - -.. parsed-literal:: - - [4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] - - -.. code:: ipython2 - - J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ") - - -.. parsed-literal:: - - [4 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]] - - -.. code:: ipython2 - - J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ") - - -.. parsed-literal:: - - [3 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]] - - -Appendix: The source code. --------------------------- - -:: - - fourth == rest_two rest first - ?fourth == [] [fourth] [] ifte - first_two == uncons uncons pop - ccons == cons cons - cinf == cons infra - rest_two == rest rest - - _Tree_T> == [dipd] cinf - _Tree_T< == [dipdd] cinf - - _Tree_add_P == over [popop popop first] nullary - _Tree_add_T> == ccons _Tree_T< - _Tree_add_T< == ccons _Tree_T> - _Tree_add_Ee == pop swap roll< rest_two ccons - _Tree_add_R == _Tree_add_P [_Tree_add_T>] [_Tree_add_Ee] [_Tree_add_T<] cmp - _Tree_add_E == [pop] dipd Tree-new - - _Tree_iter_order_left == [cons dip] dupdip - _Tree_iter_order_current == [[F] dupdip] dip - _Tree_iter_order_right == [fourth] dip i - _Tree_iter_order_R == _Tree_iter_order_left _Tree_iter_order_current _Tree_iter_order_right - - _Tree_get_P == over [pop popop first] nullary - _Tree_get_T> == [fourth] dipd i - _Tree_get_T< == [third] dipd i - _Tree_get_E == popop second - _Tree_get_R == _Tree_get_P [_Tree_get_T>] [_Tree_get_E] [_Tree_get_T<] cmp - - _Tree_delete_rightmost == [?fourth] [fourth] while - _Tree_delete_clear_stuff == roll> popop rest - _Tree_delete_del == dip cons dipd swap - _Tree_delete_W == dup _Tree_delete_rightmost first_two over - _Tree_delete_E.0 == _Tree_delete_clear_stuff [_Tree_delete_W] _Tree_delete_del - _Tree_delete_E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[_Tree_delete_E.0] cinf]] cond - _Tree_delete_R0 == over first swap dup - _Tree_delete_R1 == cons roll> [_Tree_T>] [_Tree_delete_E] [_Tree_T<] cmp - - Tree-new == swap [[] []] ccons - Tree-add == [popop not] [_Tree_add_E] [] [_Tree_add_R] genrec - Tree-iter == [not] [pop] roll< [dupdip rest_two] cons [step] genrec - Tree-iter-order == [not] [pop] [dup third] [_Tree_iter_order_R] genrec - Tree-get == [pop not] swap [] [_Tree_get_R] genrec - Tree-delete == [pop not] [pop] [_Tree_delete_R0] [_Tree_delete_R1] genrec diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt deleted file mode 100644 index 3262e84..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Quadratic.rst.txt +++ /dev/null @@ -1,158 +0,0 @@ -.. code:: ipython2 - - from notebook_preamble import J, V, define - -`Quadratic formula `__ -======================================================================= - -Cf. -`jp-quadratic.html `__ - -:: - - -b ± sqrt(b^2 - 4 * a * c) - -------------------------------- - 2 * a - -:math:`\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -Write a straightforward program with variable names. ----------------------------------------------------- - -This math translates to Joy code in a straightforward manner. We are -going to use named variables to keep track of the arguments, then write -a definition without them. - -``-b`` -~~~~~~ - -:: - - b neg - -``sqrt(b^2 - 4 * a * c)`` -~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - b sqr 4 a c * * - sqrt - -``/2a`` -~~~~~~~ - -:: - - a 2 * / - -``±`` -~~~~~ - -There is a function ``pm`` that accepts two values on the stack and -replaces them with their sum and difference. - -:: - - pm == [+] [-] cleave popdd - -Putting Them Together -~~~~~~~~~~~~~~~~~~~~~ - -:: - - b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2 - -We use ``app2`` to compute both roots by using a quoted program -``[2a /]`` built with ``cons``. - -Derive a definition. --------------------- - -Working backwards we use ``dip`` and ``dipd`` to extract the code from -the variables: - -:: - - b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2 - b [neg] dupdip sqr 4 a c * * - sqrt pm a 2 * [/] cons app2 - b a c [[neg] dupdip sqr 4] dipd * * - sqrt pm a 2 * [/] cons app2 - b a c a [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 - b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 - -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 - - define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2') - -Let’s try it out: - -.. code:: ipython2 - - J('3 1 1 quadratic') - - -.. parsed-literal:: - - -0.3819660112501051 -2.618033988749895 - - -If you look at the Joy evaluation trace you can see that the first few -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 - - V('-5 1 4 quadratic') - - -.. parsed-literal:: - - . -5 1 4 quadratic - -5 . 1 4 quadratic - -5 1 . 4 quadratic - -5 1 4 . quadratic - -5 1 4 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 - -5 1 4 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 - -5 1 4 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2 - -5 1 4 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [/] cons app2 - -5 1 4 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [/] cons app2 - -5 . [neg] dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - -5 [neg] . dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - -5 . neg -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 . -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 -5 . sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 -5 . dup mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 -5 -5 . mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 25 . 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 25 4 . 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 25 4 1 . 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 25 4 1 4 . * * - sqrt pm 1 2 * [/] cons app2 - 5 25 4 4 . * - sqrt pm 1 2 * [/] cons app2 - 5 25 16 . - sqrt pm 1 2 * [/] cons app2 - 5 9 . sqrt pm 1 2 * [/] cons app2 - 5 3.0 . pm 1 2 * [/] cons app2 - 8.0 2.0 . 1 2 * [/] cons app2 - 8.0 2.0 1 . 2 * [/] cons app2 - 8.0 2.0 1 2 . * [/] cons app2 - 8.0 2.0 2 . [/] cons app2 - 8.0 2.0 2 [/] . cons app2 - 8.0 2.0 [2 /] . app2 - [8.0] [2 /] . infra first [2.0] [2 /] infra first - 8.0 . 2 / [] swaack first [2.0] [2 /] infra first - 8.0 2 . / [] swaack first [2.0] [2 /] infra first - 4.0 . [] swaack first [2.0] [2 /] infra first - 4.0 [] . swaack first [2.0] [2 /] infra first - [4.0] . first [2.0] [2 /] infra first - 4.0 . [2.0] [2 /] infra first - 4.0 [2.0] . [2 /] infra first - 4.0 [2.0] [2 /] . infra first - 2.0 . 2 / [4.0] swaack first - 2.0 2 . / [4.0] swaack first - 1.0 . [4.0] swaack first - 1.0 [4.0] . swaack first - 4.0 [1.0] . first - 4.0 1.0 . - - 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 deleted file mode 100644 index 9159882..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Recursion_Combinators.rst.txt +++ /dev/null @@ -1,690 +0,0 @@ -.. code:: ipython2 - - from notebook_preamble import D, DefinitionWrapper, J, V, define - -Recursion Combinators -===================== - -This article describes the ``genrec`` combinator, how to use it, and -several generic specializations. - -:: - - [if] [then] [rec1] [rec2] genrec - --------------------------------------------------------------------- - [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte - -From “Recursion Theory and Joy” (j05cmp.html) by Manfred von Thun: - - “The genrec combinator takes four program parameters in addition to - whatever data parameters it needs. Fourth from the top is an if-part, - followed by a then-part. If the if-part yields true, then the - then-part is executed and the combinator terminates. The other two - parameters are the rec1-part and the rec2-part. If the if-part yields - false, the rec1-part is executed. Following that the four program - parameters and the combinator are again pushed onto the stack bundled - up in a quoted form. Then the rec2-part is executed, where it will - find the bundled form. Typically it will then execute the bundled - form, either with i or with app2, or some other combinator.” - -Designing Recursive Functions ------------------------------ - -The way to design one of these is to fix your base case and test and -then treat ``R1`` and ``R2`` as an else-part “sandwiching” a quotation -of the whole function. - -For example, given a (general recursive) function ``F``: - -:: - - F == [I] [T] [R1] [R2] genrec - == [I] [T] [R1 [F] R2] ifte - -If the ``[I]`` predicate is false you must derive ``R1`` and ``R2`` -from: - -:: - - ... R1 [F] R2 - -Set the stack arguments in front and figure out what ``R1`` and ``R2`` -have to do to apply the quoted ``[F]`` in the proper way. - -Primitive Recursive Functions ------------------------------ - -Primitive recursive functions are those where ``R2 == i``. - -:: - - P == [I] [T] [R] primrec - == [I] [T] [R [P] i] ifte - == [I] [T] [R P] ifte - -`Hylomorphism `__ ------------------------------------------------------------------------------------- - -A -`hylomorphism `__ -is a recursive function ``H :: A -> C`` that converts a value of type -``A`` into a value of type ``C`` by means of: - -- A generator ``G :: A -> (B, A)`` -- A combiner ``F :: (B, C) -> C`` -- A predicate ``P :: A -> Bool`` to detect the base case -- A base case value ``c :: C`` -- Recursive calls (zero or more); it has a “call stack in the form of a - cons list”. - -It may be helpful to see this function implemented in imperative Python -code. - -.. code:: ipython2 - - 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 - - return H - -Cf. `“Bananas, Lenses, & Barbed -Wire” `__ - -Note that during evaluation of ``H()`` the intermediate ``b`` values are -stored in the Python call stack. This is what is meant by “call stack in -the form of a cons list”. - -Hylomorphism in Joy -------------------- - -We can define a combinator ``hylomorphism`` that will make a -hylomorphism combinator ``H`` from constituent parts. - -:: - - H == [P] c [G] [F] hylomorphism - -The function ``H`` is recursive, so we start with ``ifte`` and set the -else-part to some function ``J`` that will contain a quoted copy of -``H``. (The then-part just discards the leftover ``a`` and replaces it -with the base case value ``c``.) - -:: - - H == [P] [pop c] [J] ifte - -The else-part ``J`` gets just the argument ``a`` on the stack. - -:: - - a J - a G The first thing to do is use the generator G - aa b which produces b and a new aa - aa b [H] dip we recur with H on the new aa - aa H b F and run F on the result. - -This gives us a definition for ``J``. - -:: - - J == G [H] dip F - -Plug it in and convert to genrec. - -:: - - H == [P] [pop c] [G [H] dip F] ifte - H == [P] [pop c] [G] [dip F] genrec - -This is the form of a hylomorphism in Joy, which nicely illustrates that -it is a simple specialization of the general recursion combinator. - -:: - - H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec - -Derivation of ``hylomorphism`` combinator ------------------------------------------ - -Now we just need to derive a definition that builds the ``genrec`` -arguments out of the pieces given to the ``hylomorphism`` combinator. - -:: - - [P] c [G] [F] hylomorphism - ------------------------------------------ - [P] [pop c] [G] [dip F] genrec - -Working in reverse: - -- Use ``swoncat`` twice to decouple ``[c]`` and ``[F]``. -- Use ``unit`` to dequote ``c``. -- Use ``dipd`` to untangle ``[unit [pop] swoncat]`` from the givens. - -So: - -:: - - H == [P] [pop c] [G] [dip F] genrec - [P] [c] [pop] swoncat [G] [F] [dip] swoncat genrec - [P] c unit [pop] swoncat [G] [F] [dip] swoncat genrec - [P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec - -At this point all of the arguments (givens) to the hylomorphism are to -the left so we have a definition for ``hylomorphism``: - -:: - - hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec - -.. code:: ipython2 - - define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec') - -Example: Finding `Triangular Numbers `__ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Let’s write a function that, given a positive integer, returns the sum -of all positive integers less than that one. (In this case the types -``A``, ``B`` and ``C`` are all ``int``.) - -To sum a range of integers from 0 to *n* - 1: - -- ``[P]`` is ``[1 <=]`` -- ``c`` is ``0`` -- ``[G]`` is ``[-- dup]`` -- ``[F]`` is ``[+]`` - -.. code:: ipython2 - - define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism') - -Let’s try it: - -.. code:: ipython2 - - J('5 triangular_number') - - -.. parsed-literal:: - - 10 - - -.. code:: ipython2 - - J('[0 1 2 3 4 5 6] [triangular_number] map') - - -.. parsed-literal:: - - [0 0 1 3 6 10 15] - - -Four Specializations --------------------- - -There are at least four kinds of recursive combinator, depending on two -choices. The first choice is whether the combiner function ``F`` should -be evaluated during the recursion or pushed into the pending expression -to be “collapsed” at the end. The second choice is whether the combiner -needs to operate on the current value of the datastructure or the -generator’s output, in other words, whether ``F`` or ``G`` should run -first in the recursive branch. - -:: - - H1 == [P] [pop c] [G ] [dip F] genrec - H2 == c swap [P] [pop] [G [F] dip ] [i] genrec - H3 == [P] [pop c] [ [G] dupdip ] [dip F] genrec - H4 == c swap [P] [pop] [ [F] dupdip G] [i] genrec - -The working of the generator function ``G`` differs slightly for each. -Consider the recursive branches: - -:: - - ... a G [H1] dip F w/ a G == a′ b - - ... c a G [F] dip H2 a G == b a′ - - ... a [G] dupdip [H3] dip F a G == a′ - - ... c a [F] dupdip G H4 a G == a′ - -The following four sections illustrate how these work, omitting the -predicate evaluation. - -``H1`` -~~~~~~ - -:: - - H1 == [P] [pop c] [G] [dip F] genrec - -Iterate n times. - -:: - - ... a G [H1] dip F - ... a′ b [H1] dip F - ... a′ H1 b F - ... a′ G [H1] dip F b F - ... a″ b′ [H1] dip F b F - ... a″ H1 b′ F b F - ... a″ G [H1] dip F b′ F b F - ... a‴ b″ [H1] dip F b′ F b F - ... a‴ H1 b″ F b′ F b F - ... a‴ pop c b″ F b′ F b F - ... c b″ F b′ F b F - ... d b′ F b F - ... d′ b F - ... d″ - -This form builds up a pending expression (continuation) that contains -the intermediate results along with the pending combiner functions. When -the base case is reached the last term is replaced by the identity value -``c`` and the continuation “collapses” into the final result using the -combiner ``F``. - -``H2`` -~~~~~~ - -When you can start with the identity value ``c`` on the stack and the -combiner ``F`` can operate as you go using the intermediate results -immediately rather than queuing them up, use this form. An important -difference is that the generator function must return its results in the -reverse order. - -:: - - H2 == c swap [P] [pop] [G [F] dip] primrec - - ... c a G [F] dip H2 - ... c b a′ [F] dip H2 - ... c b F a′ H2 - ... d a′ H2 - ... d a′ G [F] dip H2 - ... d b′ a″ [F] dip H2 - ... d b′ F a″ H2 - ... d′ a″ H2 - ... d′ a″ G [F] dip H2 - ... d′ b″ a‴ [F] dip H2 - ... d′ b″ F a‴ H2 - ... d″ a‴ H2 - ... d″ a‴ pop - ... d″ - -``H3`` -~~~~~~ - -If you examine the traces above you’ll see that the combiner ``F`` only -gets to operate on the results of ``G``, it never “sees” the first value -``a``. If the combiner and the generator both need to work on the -current value then ``dup`` must be used, and the generator must produce -one item instead of two (the b is instead the duplicate of a.) - -:: - - H3 == [P] [pop c] [[G] dupdip] [dip F] genrec - - ... a [G] dupdip [H3] dip F - ... a G a [H3] dip F - ... a′ a [H3] dip F - ... a′ H3 a F - ... a′ [G] dupdip [H3] dip F a F - ... a′ G a′ [H3] dip F a F - ... a″ a′ [H3] dip F a F - ... a″ H3 a′ F a F - ... a″ [G] dupdip [H3] dip F a′ F a F - ... a″ G a″ [H3] dip F a′ F a F - ... a‴ a″ [H3] dip F a′ F a F - ... a‴ H3 a″ F a′ F a F - ... a‴ pop c a″ F a′ F a F - ... c a″ F a′ F a F - ... d a′ F a F - ... d′ a F - ... d″ - -``H4`` -~~~~~~ - -And, last but not least, if you can combine as you go, starting with -``c``, and the combiner ``F`` needs to work on the current item, this is -the form: - -:: - - H4 == c swap [P] [pop] [[F] dupdip G] primrec - - ... c a [F] dupdip G H4 - ... c a F a G H4 - ... d a G H4 - ... d a′ H4 - ... d a′ [F] dupdip G H4 - ... d a′ F a′ G H4 - ... d′ a′ G H4 - ... d′ a″ H4 - ... d′ a″ [F] dupdip G H4 - ... d′ a″ F a″ G H4 - ... d″ a″ G H4 - ... d″ a‴ H4 - ... d″ a‴ pop - ... d″ - -Anamorphism ------------ - -An anamorphism can be defined as a hylomorphism that uses ``[]`` for -``c`` and ``swons`` for ``F``. An anamorphic function builds a list of -values. - -:: - - A == [P] [] [G] [swons] hylomorphism - -``range`` et. al. An example of an anamorphism is the ``range`` function which generates the list of integers from 0 to *n* - 1 given *n*. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Each of the above variations can be used to make four slightly different -``range`` functions. - -``range`` with ``H1`` -^^^^^^^^^^^^^^^^^^^^^ - -:: - - H1 == [P] [pop c] [G] [dip F] genrec - == [0 <=] [pop []] [-- dup] [dip swons] genrec - -.. code:: ipython2 - - define('range == [0 <=] [] [-- dup] [swons] hylomorphism') - -.. code:: ipython2 - - J('5 range') - - -.. parsed-literal:: - - [4 3 2 1 0] - - -``range`` with ``H2`` -^^^^^^^^^^^^^^^^^^^^^ - -:: - - H2 == c swap [P] [pop] [G [F] dip] primrec - == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec - -.. code:: ipython2 - - define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec') - -.. code:: ipython2 - - J('5 range_reverse') - - -.. parsed-literal:: - - [0 1 2 3 4] - - -``range`` with ``H3`` -^^^^^^^^^^^^^^^^^^^^^ - -:: - - H3 == [P] [pop c] [[G] dupdip] [dip F] genrec - == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec - -.. code:: ipython2 - - define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec') - -.. code:: ipython2 - - J('5 ranger') - - -.. parsed-literal:: - - [5 4 3 2 1] - - -``range`` with ``H4`` -^^^^^^^^^^^^^^^^^^^^^ - -:: - - H4 == c swap [P] [pop] [[F] dupdip G ] primrec - == [] swap [0 <=] [pop] [[swons] dupdip --] primrec - -.. code:: ipython2 - - define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec') - -.. code:: ipython2 - - J('5 ranger_reverse') - - -.. parsed-literal:: - - [1 2 3 4 5] - - -Hopefully this illustrates the workings of the variations. For more -insight you can run the cells using the ``V()`` function instead of the -``J()`` function to get a trace of the Joy evaluation. - -Catamorphism ------------- - -A catamorphism can be defined as a hylomorphism that uses -``[uncons swap]`` for ``[G]`` and ``[[] =]`` (or just ``[not]``) for the -predicate ``[P]``. A catamorphic function tears down a list term-by-term -and makes some new value. - -:: - - C == [not] c [uncons swap] [F] hylomorphism - -.. code:: ipython2 - - define('swuncons == uncons swap') # Awkward name. - -An example of a catamorphism is the sum function. - -:: - - sum == [not] 0 [swuncons] [+] hylomorphism - -.. code:: ipython2 - - define('sum == [not] 0 [swuncons] [+] hylomorphism') - -.. code:: ipython2 - - J('[5 4 3 2 1] sum') - - -.. parsed-literal:: - - 15 - - -The ``step`` combinator -~~~~~~~~~~~~~~~~~~~~~~~ - -The ``step`` combinator will usually be better to use than -``catamorphism``. - -.. code:: ipython2 - - J('[step] help') - - -.. parsed-literal:: - - Run a quoted program on each item in a sequence. - :: - - ... [] [Q] . step - ----------------------- - ... . - - - ... [a] [Q] . step - ------------------------ - ... a . Q - - - ... [a b c] [Q] . step - ---------------------------------------- - ... a . Q [b c] [Q] step - - The step combinator executes the quotation on each member of the list - on top of the stack. - - - -.. code:: ipython2 - - define('sum == 0 swap [+] step') - -.. code:: ipython2 - - J('[5 4 3 2 1] sum') - - -.. parsed-literal:: - - 15 - - -Example: Factorial Function ---------------------------- - -For the Factorial function: - -:: - - H4 == c swap [P] [pop] [[F] dupdip G] primrec - -With: - -:: - - c == 1 - F == * - G == -- - P == 1 <= - -.. code:: ipython2 - - define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec') - -.. code:: ipython2 - - J('5 factorial') - - -.. parsed-literal:: - - 120 - - -Example: ``tails`` ------------------- - -An example of a paramorphism for lists given in the `“Bananas…” -paper `__ -is ``tails`` which returns the list of “tails” of a list. - -:: - - [1 2 3] tails - -------------------- - [[] [3] [2 3]] - -We can build as we go, and we want ``F`` to run after ``G``, so we use -pattern ``H2``: - -:: - - H2 == c swap [P] [pop] [G [F] dip] primrec - -We would use: - -:: - - c == [] - F == swons - G == rest dup - P == not - -.. code:: ipython2 - - define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec') - -.. code:: ipython2 - - J('[1 2 3] tails') - - -.. parsed-literal:: - - [[] [3] [2 3]] - - -Conclusion: Patterns of Recursion ---------------------------------- - -Our story so far… - -Hylo-, Ana-, Cata- -~~~~~~~~~~~~~~~~~~ - -:: - - H == [P ] [pop c ] [G ] [dip F ] genrec - A == [P ] [pop []] [G ] [dip swap cons] genrec - C == [not] [pop c ] [uncons swap] [dip F ] genrec - -Para-, ?-, ?- -~~~~~~~~~~~~~ - -:: - - P == c swap [P ] [pop] [[F ] dupdip G ] primrec - ? == [] swap [P ] [pop] [[swap cons] dupdip G ] primrec - ? == c swap [not] [pop] [[F ] dupdip uncons swap] primrec - -Appendix: Fun with Symbols --------------------------- - -:: - - |[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)] - -`“Bananas, Lenses, & Barbed -Wire” `__ - -:: - - (|...|) [(...)] [<...>] - -I think they are having slightly too much fun with the symbols. However, -“Too much is always better than not enough.” diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt deleted file mode 100644 index 0f90445..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Replacing.rst.txt +++ /dev/null @@ -1,147 +0,0 @@ -Replacing Functions in the Dictionary -===================================== - -For now, there is no way to define new functions from within the Joy -language. All functions (and the interpreter) all accept and return a -dictionary parameter (in addition to the stack and expression) so that -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. - -.. code:: ipython2 - - from notebook_preamble import D, J, V - -A long trace ------------- - -.. code:: ipython2 - - V('[23 18] average') - - -.. parsed-literal:: - - . [23 18] average - [23 18] . average - [23 18] . [sum 1.0 *] [size] cleave / - [23 18] [sum 1.0 *] . [size] cleave / - [23 18] [sum 1.0 *] [size] . cleave / - [23 18] [sum 1.0 *] [size] . [i] app2 [popd] dip / - [23 18] [sum 1.0 *] [size] [i] . app2 [popd] dip / - [23 18] [[sum 1.0 *] [23 18]] [i] . infra first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] [sum 1.0 *] . i [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] . sum 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41 . 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41 1.0 . * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41.0 . [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41.0 [[23 18]] . swaack first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] [41.0] . first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] 41.0 . [[size] [23 18]] [i] infra first [popd] dip / - [23 18] 41.0 [[size] [23 18]] . [i] infra first [popd] dip / - [23 18] 41.0 [[size] [23 18]] [i] . infra first [popd] dip / - [23 18] [size] . i [41.0 [23 18]] swaack first [popd] dip / - [23 18] . size [41.0 [23 18]] swaack first [popd] dip / - [23 18] . 0 swap [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - [23 18] 0 . swap [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 0 [23 18] . [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 0 [23 18] [pop ++] . step [41.0 [23 18]] swaack first [popd] dip / - 0 23 [pop ++] . i [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 0 23 . pop ++ [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 0 . ++ [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 1 . [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 1 [18] . [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 1 [18] [pop ++] . step [41.0 [23 18]] swaack first [popd] dip / - 1 18 [pop ++] . i [41.0 [23 18]] swaack first [popd] dip / - 1 18 . pop ++ [41.0 [23 18]] swaack first [popd] dip / - 1 . ++ [41.0 [23 18]] swaack first [popd] dip / - 2 . [41.0 [23 18]] swaack first [popd] dip / - 2 [41.0 [23 18]] . swaack first [popd] dip / - [23 18] 41.0 [2] . first [popd] dip / - [23 18] 41.0 2 . [popd] dip / - [23 18] 41.0 2 [popd] . dip / - [23 18] 41.0 . popd 2 / - 41.0 . 2 / - 41.0 2 . / - 20.5 . - - -Replacing ``size`` with a Python version ----------------------------------------- - -Both ``sum`` and ``size`` each convert a sequence to a single value. - -:: - - sum == 0 swap [+] step - size == 0 swap [pop ++] step - -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 - - 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 - -Now we replace the old version in the dictionary with the new version, -and re-evaluate the expression. - -.. code:: ipython2 - - D['size'] = size - -A shorter trace ---------------- - -You can see that ``size`` now executes in a single step. - -.. code:: ipython2 - - V('[23 18] average') - - -.. parsed-literal:: - - . [23 18] average - [23 18] . average - [23 18] . [sum 1.0 *] [size] cleave / - [23 18] [sum 1.0 *] . [size] cleave / - [23 18] [sum 1.0 *] [size] . cleave / - [23 18] [sum 1.0 *] [size] . [i] app2 [popd] dip / - [23 18] [sum 1.0 *] [size] [i] . app2 [popd] dip / - [23 18] [[sum 1.0 *] [23 18]] [i] . infra first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] [sum 1.0 *] . i [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] . sum 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41 . 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41 1.0 . * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41.0 . [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41.0 [[23 18]] . swaack first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] [41.0] . first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] 41.0 . [[size] [23 18]] [i] infra first [popd] dip / - [23 18] 41.0 [[size] [23 18]] . [i] infra first [popd] dip / - [23 18] 41.0 [[size] [23 18]] [i] . infra first [popd] dip / - [23 18] [size] . i [41.0 [23 18]] swaack first [popd] dip / - [23 18] . size [41.0 [23 18]] swaack first [popd] dip / - 2 . [41.0 [23 18]] swaack first [popd] dip / - 2 [41.0 [23 18]] . swaack first [popd] dip / - [23 18] 41.0 [2] . first [popd] dip / - [23 18] 41.0 2 . [popd] dip / - [23 18] 41.0 2 [popd] . dip / - [23 18] 41.0 . popd 2 / - 41.0 . 2 / - 41.0 2 . / - 20.5 . - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Square_Spiral.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Square_Spiral.rst.txt deleted file mode 100644 index 7b5e67a..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Square_Spiral.rst.txt +++ /dev/null @@ -1,421 +0,0 @@ -.. code:: ipython3 - - from notebook_preamble import J, V, define - -Square Spiral Example Joy Code -============================== - -Here is the example of Joy code from the ``README`` file: - -:: - - [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte - -It might seem unreadable but with a little familiarity it becomes just -as legible as any other notation. Some layout helps: - -:: - - [ [[abs] ii <=] - [ - [<>] [pop !-] || - ] && - ] - [[ !-] [[++]] [[--]] ifte dip] - [[pop !-] [--] [++] ifte ] - ifte - -This function accepts two integers on the stack and increments or -decrements one of them such that the new pair of numbers is the next -coordinate pair in a square spiral (like the kind used to construct an -Ulam Spiral). - -Original Form -------------- - -It's adapted from `the original code on -StackOverflow `__: - - If all you're trying to do is generate the first N points in the - spiral (without the original problem's constraint of masking to an N - x M region), the code becomes very simple: - -:: - - void spiral(const int N) - { - int x = 0; - int y = 0; - for(int i = 0; i < N; ++i) - { - cout << x << '\t' << y << '\n'; - if(abs(x) <= abs(y) && (x != y || x >= 0)) - x += ((y >= 0) ? 1 : -1); - else - y += ((x >= 0) ? -1 : 1); - } - } - -Translation to Joy ------------------- - -I'm going to make a function that take two ints (``x`` and ``y``) and -generates the next pair, we'll turn it into a generator later using the -``x`` combinator. - -First Boolean Predicate -~~~~~~~~~~~~~~~~~~~~~~~ - -We need a function that computes ``abs(x) <= abs(y)``, we can use ``ii`` -to apply ``abs`` to both values and then compare them with ``<=``: - -:: - - [abs] ii <= - -I've defined two short-circuiting Boolean combinators ``&&`` and ``||`` -that each accept two quoted predicate programs, run the first, and -conditionally run the second only if required (to compute the final -Boolean value). They run their predicate arguments ``nullary``. - -.. code:: ipython3 - - define('&& [nullary] cons [nullary [0]] dip branch') - define('|| [nullary] cons [nullary] dip [1] branch') - -Given those, we can define ``x != y || x >= 0`` as: - -:: - - [<>] [pop 0 >=] || - -And ``(abs(x) <= abs(y) && (x != y || x >= 0))`` as: - -:: - - [[abs] ii <=] [[<>] [pop 0 >=] ||] && - -It's a little rough, but, as I say, with a little familiarity it becomes -legible. - -The Increment / Decrement Branches -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Turning to the branches of the main ``if`` statement: - -:: - - x += ((y >= 0) ? 1 : -1); - -Rewrite as a hybrid (pseudo-code) ``ifte`` expression: - -:: - - [y >= 0] [x += 1] [X -= 1] ifte - -Change each C phrase to Joy code: - -:: - - [0 >=] [[++] dip] [[--] dip] ifte - -Factor out the dip from each branch: - -:: - - [0 >=] [[++]] [[--]] ifte dip - -Similar logic applies to the other branch: - -:: - - y += ((x >= 0) ? -1 : 1); - - [x >= 0] [y -= 1] [y += 1] ifte - - [pop 0 >=] [--] [++] ifte - -"Not Negative" -~~~~~~~~~~~~~~ - -.. code:: ipython3 - - define('!- 0 >=') - -Putting the Pieces Together ---------------------------- - -We can assemble the three functions we just defined in quotes and give -them them to the ``ifte`` combinator. With some arrangement to show off -the symmetry of the two branches, we have: - -:: - - [[[abs] ii <=] [[<>] [pop !-] ||] &&] - [[ !-] [[++]] [[--]] ifte dip] - [[pop !-] [--] [++] ifte ] - ifte - -As I was writing this up I realized that, since the ``&&`` combinator -doesn't consume the stack (below its quoted args), I can unquote the -predicate, swap the branches, and use the ``branch`` combinator instead -of ``ifte``: - -:: - - [[abs] ii <=] [[<>] [pop !-] ||] && - [[pop !-] [--] [++] ifte ] - [[ !-] [[++]] [[--]] ifte dip] - branch - -.. code:: ipython3 - - define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte') - -Let's try it out: - -.. code:: ipython3 - - J('0 0 spiral_next') - - -.. parsed-literal:: - - 1 0 - - -.. code:: ipython3 - - J('1 0 spiral_next') - - -.. parsed-literal:: - - 1 -1 - - -.. code:: ipython3 - - J('1 -1 spiral_next') - - -.. parsed-literal:: - - 0 -1 - - -.. code:: ipython3 - - J('0 -1 spiral_next') - - -.. parsed-literal:: - - -1 -1 - - -Turning it into a Generator with ``x`` --------------------------------------- - -It can be used with the x combinator to make a kind of generator for -spiral square coordinates. - -We can use ``codireco`` to make a generator - -:: - - codireco ::= cons dip rest cons - -It will look like this: - -:: - - [value [F] codireco] - -Here's a trace of how it works: - -:: - - [0 [dup ++] codireco] . x - [0 [dup ++] codireco] . 0 [dup ++] codireco - [0 [dup ++] codireco] 0 . [dup ++] codireco - [0 [dup ++] codireco] 0 [dup ++] . codireco - [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons - [0 [dup ++] codireco] [0 dup ++] . dip rest cons - . 0 dup ++ [0 [dup ++] codireco] rest cons - 0 . dup ++ [0 [dup ++] codireco] rest cons - 0 0 . ++ [0 [dup ++] codireco] rest cons - 0 1 . [0 [dup ++] codireco] rest cons - 0 1 [0 [dup ++] codireco] . rest cons - 0 1 [[dup ++] codireco] . cons - 0 [1 [dup ++] codireco] . - -But first we have to change the ``spiral_next`` function to work on a -quoted pair of integers, and leave a copy of the pair on the stack. -From: - -:: - - y x spiral_next - --------------------- - y' x' - -to: - -:: - - [x y] [spiral_next] infra - ------------------------------- - [x' y'] - -.. code:: ipython3 - - J('[0 0] [spiral_next] infra') - - -.. parsed-literal:: - - [0 1] - - -So our generator is: - -:: - - [[x y] [dup [spiral_next] infra] codireco] - -Or rather: - -:: - - [[0 0] [dup [spiral_next] infra] codireco] - -There is a function ``make_generator`` that will build the generator for -us out of the value and stepper function: - -:: - - [0 0] [dup [spiral_next] infra] make_generator - ---------------------------------------------------- - [[0 0] [dup [spiral_next] infra] codireco] - -Here it is in action: - -.. code:: ipython3 - - J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop') - - -.. parsed-literal:: - - [0 0] [0 1] [-1 1] [-1 0] - - -Four ``x`` combinators, four pairs of coordinates. - -Conclusion ----------- - -So that's an example of Joy code. It's a straightforward translation of -the original. It's a little long for a single definition, you might -break it up like so: - -:: - - _spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] && - - _spn_T ::= [ !-] [[++]] [[--]] ifte dip - _spn_E ::= [pop !-] [--] [++] ifte - - spiral_next ::= _spn_P [_spn_E] [_spn_T] branch - -This way it's easy to see that the function is a branch with two -quasi-symmetrical paths. - -We then used this function to make a simple generator of coordinate -pairs, where the next pair in the series can be generated at any time by -using the ``x`` combinator on the generator (which is just a quoted -expression containing a copy of the current pair and the "stepper -function" to generate the next pair from that.) - -.. code:: ipython3 - - define('_spn_P [[abs] ii <=] [[<>] [pop !-] ||] &&') - define('_spn_T [!-] [[++]] [[--]] ifte dip') - define('_spn_E [pop !-] [--] [++] ifte') - define('spiral_next _spn_P [_spn_E] [_spn_T] branch') - -.. code:: ipython3 - - V('23 18 spiral_next') - - -.. parsed-literal:: - - . 23 18 spiral_next - 23 . 18 spiral_next - 23 18 . spiral_next - 23 18 . _spn_P [_spn_E] [_spn_T] branch - 23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch - 23 18 . 0 [_spn_E] [_spn_T] branch - 23 18 0 . [_spn_E] [_spn_T] branch - 23 18 0 [_spn_E] . [_spn_T] branch - 23 18 0 [_spn_E] [_spn_T] . branch - 23 18 . _spn_E - 23 18 . [pop !-] [--] [++] ifte - 23 18 [pop !-] . [--] [++] ifte - 23 18 [pop !-] [--] . [++] ifte - 23 18 [pop !-] [--] [++] . ifte - 23 18 [pop !-] [--] [++] . [nullary not] dipd branch - 23 18 [pop !-] [--] [++] [nullary not] . dipd branch - 23 18 [pop !-] . nullary not [--] [++] branch - 23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch - 23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch - 23 18 [pop !-] [stack] . dip infra first not [--] [++] branch - 23 18 . stack [pop !-] infra first not [--] [++] branch - 23 18 [18 23] . [pop !-] infra first not [--] [++] branch - 23 18 [18 23] [pop !-] . infra first not [--] [++] branch - 23 18 . pop !- [18 23] swaack first not [--] [++] branch - 23 . !- [18 23] swaack first not [--] [++] branch - 23 . 0 >= [18 23] swaack first not [--] [++] branch - 23 0 . >= [18 23] swaack first not [--] [++] branch - True . [18 23] swaack first not [--] [++] branch - True [18 23] . swaack first not [--] [++] branch - 23 18 [True] . first not [--] [++] branch - 23 18 True . not [--] [++] branch - 23 18 False . [--] [++] branch - 23 18 False [--] . [++] branch - 23 18 False [--] [++] . branch - 23 18 . -- - 23 17 . - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/The_Four_Operations.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/The_Four_Operations.rst.txt deleted file mode 100644 index 2dc77d3..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/The_Four_Operations.rst.txt +++ /dev/null @@ -1,336 +0,0 @@ -The Four Fundamental Operations of Definite Action -================================================== - -All definite actions (computer program) can be defined by four -fundamental patterns of combination: - -1. Sequence -2. Branch -3. Loop -4. Parallel - -Sequence --------- - -Do one thing after another. In joy this is represented by putting two -symbols together, juxtaposition: - -:: - - foo bar - -Operations have inputs and outputs. The outputs of ``foo`` must be -compatible in “arity”, type, and shape with the inputs of ``bar``. - -Branch ------- - -Do one thing or another. - -:: - - boolean [F] [T] branch - - - t [F] [T] branch - ---------------------- - T - - - f [F] [T] branch - ---------------------- - F - - - branch == unit cons swap pick i - - boolean [F] [T] branch - boolean [F] [T] unit cons swap pick i - boolean [F] [[T]] cons swap pick i - boolean [[F] [T]] swap pick i - [[F] [T]] boolean pick i - [F-or-T] i - -Given some branch function ``G``: - -:: - - G == [F] [T] branch - -Used in a sequence like so: - -:: - - foo G bar - -The inputs and outputs of ``F`` and ``T`` must be compatible with the -outputs for ``foo`` and the inputs of ``bar``, respectively. - -:: - - foo F bar - - foo T bar - -``ifte`` -~~~~~~~~ - -Often it will be easier on the programmer to write branching code with -the predicate specified in a quote. The ``ifte`` combinator provides -this (``T`` for “then” and ``E`` for “else”): - -:: - - [P] [T] [E] ifte - -Defined in terms of ``branch``: - -:: - - ifte == [nullary not] dip branch - -In this case, ``P`` must be compatible with the stack and return a -Boolean value, and ``T`` and ``E`` both must be compatible with the -preceeding and following functions, as described above for ``F`` and -``T``. (Note that in the current implementation we are depending on -Python for the underlying semantics, so the Boolean value doesn’t *have* -to be Boolean because Python’s rules for “truthiness” will be used to -evaluate it. I reflect this in the structure of the stack effect comment -of ``branch``, it will only accept Boolean values, and in the definition -of ``ifte`` above by including ``not`` in the quote, which also has the -effect that the subject quotes are in the proper order for ``branch``.) - -Loop ----- - -Do one thing zero or more times. - -:: - - boolean [Q] loop - - - t [Q] loop - ---------------- - Q [Q] loop - - - ... f [Q] loop - -------------------- - ... - -The ``loop`` combinator generates a copy of itself in the true branch. -This is the hallmark of recursive defintions. In Thun there is no -equivalent to conventional loops. (There is, however, the ``x`` -combinator, defined as ``x == dup i``, which permits recursive -constructs that do not need to be directly self-referential, unlike -``loop`` and ``genrec``.) - -:: - - loop == [] swap [dup dip loop] cons branch - - boolean [Q] loop - boolean [Q] [] swap [dup dip loop] cons branch - boolean [] [Q] [dup dip loop] cons branch - boolean [] [[Q] dup dip loop] branch - -In action the false branch does nothing while the true branch does: - -:: - - t [] [[Q] dup dip loop] branch - [Q] dup dip loop - [Q] [Q] dip loop - Q [Q] loop - -Because ``loop`` expects and consumes a Boolean value, the ``Q`` -function must be compatible with the previous stack *and itself* with a -boolean flag for the next iteration: - -:: - - Q == G b - - Q [Q] loop - G b [Q] loop - G Q [Q] loop - G G b [Q] loop - G G Q [Q] loop - G G G b [Q] loop - G G G - -``while`` -~~~~~~~~~ - -Keep doing ``B`` *while* some predicate ``P`` is true. This is -convenient as the predicate function is made nullary automatically and -the body function can be designed without regard to leaving a Boolean -flag for the next iteration: - -:: - - [P] [B] while - -------------------------------------- - [P] nullary [B [P] nullary] loop - - - while == swap [nullary] cons dup dipd concat loop - - - [P] [B] while - [P] [B] swap [nullary] cons dup dipd concat loop - [B] [P] [nullary] cons dup dipd concat loop - [B] [[P] nullary] dup dipd concat loop - [B] [[P] nullary] [[P] nullary] dipd concat loop - [P] nullary [B] [[P] nullary] concat loop - [P] nullary [B [P] nullary] loop - -Parallel --------- - -The *parallel* operation indicates that two (or more) functions *do not -interfere* with each other and so can run in parallel. The main -difficulty in this sort of thing is orchestrating the recombining -(“join” or “wait”) of the results of the functions after they finish. - -The current implementaions and the following definitions *are not -actually parallel* (yet), but there is no reason they couldn’t be -reimplemented in terms of e.g. Python threads. I am not concerned with -performance of the system just yet, only the elegance of the code it -allows us to write. - -``cleave`` -~~~~~~~~~~ - -Joy has a few parallel combinators, the main one being ``cleave``: - -:: - - ... x [A] [B] cleave - --------------------------------------------------------- - ... [x ...] [A] infra first [x ...] [B] infra first - --------------------------------------------------------- - ... a b - -The ``cleave`` combinator expects a value and two quotes and it executes -each quote in “separate universes” such that neither can affect the -other, then it takes the first item from the stack in each universe and -replaces the value and quotes with their respective results. - -(I think this corresponds to the “fork” operator, the little -upward-pointed triangle, that takes two functions ``A :: x -> a`` and -``B :: x -> b`` and returns a function ``F :: x -> (a, b)``, in Conal -Elliott’s “Compiling to Categories” paper, et. al.) - -Just a thought, if you ``cleave`` two jobs and one requires more time to -finish than the other you’d like to be able to assign resources -accordingly so that they both finish at the same time. - -“Apply” Functions -~~~~~~~~~~~~~~~~~ - -There are also ``app2`` and ``app3`` which run a single quote on more -than one value: - -:: - - ... y x [Q] app2 - --------------------------------------------------------- - ... [y ...] [Q] infra first [x ...] [Q] infra first - - - ... z y x [Q] app3 - --------------------------------- - ... [z ...] [Q] infra first - [y ...] [Q] infra first - [x ...] [Q] infra first - -Because the quoted program can be ``i`` we can define ``cleave`` in -terms of ``app2``: - -:: - - cleave == [i] app2 [popd] dip - -(I’m not sure why ``cleave`` was specified to take that value, I may -make a combinator that does the same thing but without expecting a -value.) - -:: - - clv == [i] app2 - - [A] [B] clv - ------------------ - a b - -``map`` -~~~~~~~ - -The common ``map`` function in Joy should also be though of as a -*parallel* operator: - -:: - - [a b c ...] [Q] map - -There is no reason why the implementation of ``map`` couldn’t distribute -the ``Q`` function over e.g. a pool of worker CPUs. - -``pam`` -~~~~~~~ - -One of my favorite combinators, the ``pam`` combinator is just: - -:: - - pam == [i] map - -This can be used to run any number of programs separately on the current -stack and combine their (first) outputs in a result list. - -:: - - [[A] [B] [C] ...] [i] map - ------------------------------- - [ a b c ...] - -Handling Other Kinds of Join -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``cleave`` operators and others all have pretty brutal join -semantics: everything works and we always wait for every -sub-computation. We can imagine a few different potentially useful -patterns of “joining” results from parallel combinators. - -first-to-finish -^^^^^^^^^^^^^^^ - -Thinking about variations of ``pam`` there could be one that only -returns the first result of the first-to-finish sub-program, or the -stack could be replaced by its output stack. - -The other sub-programs would be cancelled. - -“Fulminators” -^^^^^^^^^^^^^ - -Also known as “Futures” or “Promises” (by *everybody* else. “Fulminators” -is what I was going to call them when I was thinking about implementing -them in Thun.) - -The runtime could be amended to permit “thunks” representing the results -of in-progress computations to be left on the stack and picked up by -subsequent functions. These would themselves be able to leave behind -more “thunks”, the values of which depend on the eventual resolution of -the values of the previous thunks. - -In this way you can create “chains” (and more complex shapes) out of -normal-looking code that consist of a kind of call-graph interspersed -with “asyncronous” … events? - -In any case, until I can find a rigorous theory that shows that this -sort of thing works perfectly in Joy code I’m not going to worry about -it. (And I think the Categories can deal with it anyhow? Incremental -evaluation, yeah?) diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt deleted file mode 100644 index 6b9081f..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Treestep.rst.txt +++ /dev/null @@ -1,620 +0,0 @@ -Treating Trees II: ``treestep`` -=============================== - -Let’s consider a tree structure, similar to one described `“Why -functional programming matters” by John -Hughes `__, -that consists of a node value followed by zero or more child trees. (The -asterisk is meant to indicate the `Kleene -star `__.) - -:: - - tree = [] | [node tree*] - -In the spirit of ``step`` we are going to define a combinator -``treestep`` which expects a tree and three additional items: a -base-case function ``[B]``, and two quoted programs ``[N]`` and ``[C]``. - -:: - - tree [B] [N] [C] treestep - -If the current tree node is empty then just execute ``B``: - -:: - - [] [B] [N] [C] treestep - --------------------------- - [] B - -Otherwise, evaluate ``N`` on the node value, ``map`` the whole function -(abbreviated here as ``K``) over the child trees recursively, and then -combine the result with ``C``. - -:: - - [node tree*] [B] [N] [C] treestep - --------------------------------------- w/ K == [B] [N] [C] treestep - node N [tree*] [K] map C - -(Later on we’ll experiment with making ``map`` part of ``C`` so you can -use other combinators.) - -Derive the recursive function. ------------------------------- - -We can begin to derive it by finding the ``ifte`` stage that ``genrec`` -will produce. - -:: - - K == [not] [B] [R0] [R1] genrec - == [not] [B] [R0 [K] R1] ifte - -So we just have to derive ``J``: - -:: - - J == R0 [K] R1 - -The behavior of ``J`` is to accept a (non-empty) tree node and arrive at -the desired outcome. - -:: - - [node tree*] J - ------------------------------ - node N [tree*] [K] map C - -So ``J`` will have some form like: - -:: - - J == ... [N] ... [K] ... [C] ... - -Let’s dive in. First, unquote the node and ``dip`` ``N``. - -:: - - [node tree*] uncons [N] dip - node [tree*] [N] dip - node N [tree*] - -Next, ``map`` ``K`` over the child trees and combine with ``C``. - -:: - - node N [tree*] [K] map C - node N [tree*] [K] map C - node N [K.tree*] C - -So: - -:: - - J == uncons [N] dip [K] map C - -Plug it in and convert to ``genrec``: - -:: - - K == [not] [B] [J ] ifte - == [not] [B] [uncons [N] dip [K] map C] ifte - == [not] [B] [uncons [N] dip] [map C] genrec - -Extract the givens to parameterize the program. ------------------------------------------------ - -Working backwards: - -:: - - [not] [B] [uncons [N] dip] [map C] genrec - [B] [not] swap [uncons [N] dip] [map C] genrec - [B] [uncons [N] dip] [[not] swap] dip [map C] genrec - ^^^^^^^^^^^^^^^^ - [B] [[N] dip] [uncons] swoncat [[not] swap] dip [map C] genrec - [B] [N] [dip] cons [uncons] swoncat [[not] swap] dip [map C] genrec - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Extract a couple of auxiliary definitions: - -:: - - TS.0 == [[not] swap] dip - TS.1 == [dip] cons [uncons] swoncat - -:: - - [B] [N] TS.1 TS.0 [map C] genrec - [B] [N] [map C] [TS.1 TS.0] dip genrec - [B] [N] [C] [map] swoncat [TS.1 TS.0] dip genrec - -The givens are all to the left so we have our definition. - -(alternate) Extract the givens to parameterize the program. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Working backwards: - -:: - - [not] [B] [uncons [N] dip] [map C] genrec - [not] [B] [N] [dip] cons [uncons] swoncat [map C] genrec - [B] [N] [not] roll> [dip] cons [uncons] swoncat [map C] genrec - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Define ``treestep`` -------------------- - -.. code:: ipython2 - - from notebook_preamble import D, J, V, define, DefinitionWrapper - -.. code:: ipython2 - - 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 - - ''', D) - -Examples --------- - -Consider trees, the nodes of which are integers. We can find the sum of -all nodes in a tree with this function: - -:: - - sumtree == [pop 0] [] [sum +] treestep - -.. code:: ipython2 - - define('sumtree == [pop 0] [] [sum +] treestep') - -Running this function on an empty tree value gives zero: - -:: - - [] [pop 0] [] [sum +] treestep - ------------------------------------ - 0 - -.. code:: ipython2 - - J('[] sumtree') # Empty tree. - - -.. parsed-literal:: - - 0 - - -Running it on a non-empty node: - -:: - - [n tree*] [pop 0] [] [sum +] treestep - n [tree*] [[pop 0] [] [sum +] treestep] map sum + - n [ ... ] sum + - n m + - n+m - -.. code:: ipython2 - - J('[23] sumtree') # No child trees. - - -.. parsed-literal:: - - 23 - - -.. code:: ipython2 - - J('[23 []] sumtree') # Child tree, empty. - - -.. parsed-literal:: - - 23 - - -.. code:: ipython2 - - J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees. - - -.. parsed-literal:: - - 32 - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc... - - -.. parsed-literal:: - - 49 - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate "spelling". - - -.. parsed-literal:: - - 49 - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep') # Replace each node. - - -.. parsed-literal:: - - [23 [23 [23] [23]] [23] [23 []]] - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep') - - -.. parsed-literal:: - - [1 [1 [1] [1]] [1] [1 []]] - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree') - - -.. parsed-literal:: - - 6 - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function. - - -.. parsed-literal:: - - 6 - - -.. code:: ipython2 - - J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function. - - -.. parsed-literal:: - - 3 - - -Redefining the Ordered Binary Tree in terms of ``treestep``. ------------------------------------------------------------- - -:: - - Tree = [] | [[key value] left right] - -What kind of functions can we write for this with our ``treestep``? - -The pattern for processing a non-empty node is: - -:: - - node N [tree*] [K] map C - -Plugging in our BTree structure: - -:: - - [key value] N [left right] [K] map C - -Traversal -~~~~~~~~~ - -:: - - [key value] first [left right] [K] map i - key [value] [left right] [K] map i - key [left right] [K] map i - key [lkey rkey ] i - key lkey rkey - -This doesn’t quite work: - -.. code:: ipython2 - - J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep') - - -.. parsed-literal:: - - 3 'B' 'B' - - -Doesn’t work because ``map`` extracts the ``first`` item of whatever its -mapped function produces. We have to return a list, rather than -depositing our results directly on the stack. - -:: - - [key value] N [left right] [K] map C - - [key value] first [left right] [K] map flatten cons - key [left right] [K] map flatten cons - key [[lk] [rk] ] flatten cons - key [ lk rk ] cons - [key lk rk ] - -So: - -:: - - [] [first] [flatten cons] treestep - -.. code:: ipython2 - - J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first] [flatten cons] treestep') - - -.. parsed-literal:: - - [3 2 9 5 4 8 6 7] - - -There we go. - -In-order traversal -~~~~~~~~~~~~~~~~~~ - -From here: - -:: - - key [[lk] [rk]] C - key [[lk] [rk]] i - key [lk] [rk] roll< - [lk] [rk] key swons concat - [lk] [key rk] concat - [lk key rk] - -So: - -:: - - [] [i roll< swons concat] [first] treestep - -.. code:: ipython2 - - J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [uncons pop] [i roll< swons concat] treestep') - - -.. parsed-literal:: - - [2 3 4 5 6 7 8 9] - - -With ``treegrind``? -------------------- - -The ``treegrind`` function doesn’t include the ``map`` combinator, so -the ``[C]`` function must arrange to use some combinator on the quoted -recursive copy ``[K]``. With this function, the pattern for processing a -non-empty node is: - -:: - - node N [tree*] [K] C - -Plugging in our BTree structure: - -:: - - [key value] N [left right] [K] C - -.. code:: ipython2 - - J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind') - - -.. parsed-literal:: - - ['key' 'value'] 'N' [['left'] ['right']] [[not] ['B'] [uncons ['N'] dip] ['C'] genrec] 'C' - - -``treegrind`` with ``step`` ---------------------------- - -Iteration through the nodes - -.. code:: ipython2 - - J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] ["N"] [step] treegrind') - - -.. parsed-literal:: - - [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. - -.. code:: ipython2 - - J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind') - - -.. parsed-literal:: - - 44 - - -Rebuild the tree using ``map`` (imitating ``treestep``.) - -.. code:: ipython2 - - J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind') - - -.. parsed-literal:: - - [[103 0] [[102 0] [] []] [[109 0] [[105 0] [[104 0] [] []] [[108 0] [[106 0] [] [[107 0] [] []]] []]] []]] - - -Do we have the flexibility to reimplement ``Tree-get``? -------------------------------------------------------- - -I think we do: - -:: - - [B] [N] [C] treegrind - -We’ll start by saying that the base-case (the key is not in the tree) is -user defined, and the per-node function is just the query key literal: - -:: - - [B] [query_key] [C] treegrind - -This means we just have to define ``C`` from: - -:: - - [key value] query_key [left right] [K] C - -Let’s try ``cmp``: - -:: - - C == P [T>] [E] [T<] cmp - - [key value] query_key [left right] [K] P [T>] [E] [T<] cmp - -The predicate ``P`` -~~~~~~~~~~~~~~~~~~~ - -Seems pretty easy (we must preserve the value in case the keys are -equal): - -:: - - [key value] query_key [left right] [K] P - [key value] query_key [left right] [K] roll< - [key value] [left right] [K] query_key [roll< uncons swap] dip - - [key value] [left right] [K] roll< uncons swap query_key - [left right] [K] [key value] uncons swap query_key - [left right] [K] key [value] swap query_key - [left right] [K] [value] key query_key - - P == roll< [roll< uncons swap] dip - -(Possibly with a swap at the end? Or just swap ``T<`` and ``T>``.) - -So now: - -:: - - [left right] [K] [value] key query_key [T>] [E] [T<] cmp - -Becomes one of these three: - -:: - - [left right] [K] [value] T> - [left right] [K] [value] E - [left right] [K] [value] T< - -``E`` -~~~~~ - -Easy. - -:: - - E == roll> popop first - -``T<`` and ``T>`` -~~~~~~~~~~~~~~~~~ - -:: - - T< == pop [first] dip i - T> == pop [second] dip i - -Putting it together -------------------- - -:: - - 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 - -To me, that seems simpler than the ``genrec`` version. - -.. code:: ipython2 - - DefinitionWrapper.add_definitions(''' - - 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 - - ''', D) - -.. code:: ipython2 - - J('''\ - - [[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]] - - [] [5] Tree-get - - ''') - - -.. parsed-literal:: - - 15 - - -.. code:: ipython2 - - J('''\ - - [[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]] - - [pop "nope"] [25] Tree-get - - ''') - - -.. parsed-literal:: - - 'nope' - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt deleted file mode 100644 index cd85c67..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/TypeChecking.rst.txt +++ /dev/null @@ -1,171 +0,0 @@ -Type Checking -============= - -.. code:: ipython2 - - import logging, sys - - logging.basicConfig( - format='%(message)s', - stream=sys.stdout, - level=logging.INFO, - ) - -.. code:: ipython2 - - from joy.utils.types import ( - doc_from_stack_effect, - infer, - reify, - unify, - FUNCTIONS, - JoyTypeError, - ) - -.. code:: ipython2 - - D = FUNCTIONS.copy() - del D['product'] - globals().update(D) - -An Example ----------- - -.. code:: ipython2 - - fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0] - - -.. parsed-literal:: - - 25 (--) ∘ pop swap rolldown rrest ccons - 28 (a1 --) ∘ swap rolldown rrest ccons - 31 (a3 a2 a1 -- a2 a3) ∘ rolldown rrest ccons - 34 (a4 a3 a2 a1 -- a2 a3 a4) ∘ rrest ccons - 37 ([a4 a5 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ ccons - 40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘ - - -.. code:: ipython2 - - print doc_from_stack_effect(fi, fo) - - -.. parsed-literal:: - - ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) - - -.. code:: ipython2 - - from joy.parser import text_to_expression - from joy.utils.stack import stack_to_string - - -.. code:: ipython2 - - e = text_to_expression('0 1 2 [3 4]') # reverse order - print stack_to_string(e) - - -.. parsed-literal:: - - [3 4] 2 1 0 - - -.. code:: ipython2 - - u = unify(e, fi)[0] - u - - - - -.. parsed-literal:: - - {a1: 0, a2: 1, a3: 2, a4: 3, a5: 4, s2: (), s1: ()} - - - -.. code:: ipython2 - - g = reify(u, (fi, fo)) - print doc_from_stack_effect(*g) - - -.. parsed-literal:: - - (... [3 4 ] 2 1 0 -- ... [1 2 ]) - - -Unification Works “in Reverse” ------------------------------- - -.. code:: ipython2 - - e = text_to_expression('[2 3]') - -.. code:: ipython2 - - u = unify(e, fo)[0] # output side, not input side - u - - - - -.. parsed-literal:: - - {a2: 2, a3: 3, s2: (), s1: ()} - - - -.. code:: ipython2 - - g = reify(u, (fi, fo)) - print doc_from_stack_effect(*g) - - -.. parsed-literal:: - - (... [a4 a5 ] 3 2 a1 -- ... [2 3 ]) - - -Failing a Check ---------------- - -.. code:: ipython2 - - fi, fo = infer(dup, mul)[0] - - -.. parsed-literal:: - - 25 (--) ∘ dup mul - 28 (a1 -- a1 a1) ∘ mul - 31 (f1 -- f2) ∘ - 31 (i1 -- i2) ∘ - - -.. code:: ipython2 - - e = text_to_expression('"two"') - print stack_to_string(e) - - -.. parsed-literal:: - - 'two' - - -.. code:: ipython2 - - try: - unify(e, fi) - except JoyTypeError, err: - print err - - -.. parsed-literal:: - - Cannot unify 'two' and f1. - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt deleted file mode 100644 index 4c91600..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Types.rst.txt +++ /dev/null @@ -1,2968 +0,0 @@ -The Blissful Elegance of Typing Joy -=================================== - -This notebook presents a simple type inferencer for Joy code. It can -infer the stack effect of most Joy expressions. It’s built largely by -means of existing ideas and research. (A great overview of the existing -knowledge is a talk `“Type Inference in Stack-Based Programming -Languages” `__ -given by Rob Kleffner on or about 2017-03-10 as part of a course on the -history of programming languages.) - -The notebook starts with a simple inferencer based on the work of Jaanus -Pöial which we then progressively elaborate to cover more Joy semantics. -Along the way we write a simple “compiler” that emits Python code for -what I like to call Yin functions. (Yin functions are those that only -rearrange values in stacks, as opposed to Yang functions that actually -work on the values themselves.) - -Part I: Pöial’s Rules ---------------------- - -`“Typing Tools for Typeless Stack Languages” by Jaanus -Pöial `__ - -:: - - @INPROCEEDINGS{Pöial06typingtools, - author = {Jaanus Pöial}, - title = {Typing tools for typeless stack languages}, - booktitle = {In 23rd Euro-Forth Conference}, - year = {2006}, - pages = {40--46} - } - -First Rule -~~~~~~~~~~ - -This rule deals with functions (and literals) that put items on the -stack ``(-- d)``: - -:: - - (a -- b)∘(-- d) - --------------------- - (a -- b d) - -Second Rule -~~~~~~~~~~~ - -This rule deals with functions that consume items from the stack -``(a --)``: - -:: - - (a --)∘(c -- d) - --------------------- - (c a -- d) - -Third Rule -~~~~~~~~~~ - -The third rule is actually two rules. These two rules deal with -composing functions when the second one will consume one of items the -first one produces. The two types must be -`unified `__ -or a type conflict declared. - -:: - - (a -- b t[i])∘(c u[j] -- d) t <= u (t is subtype of u) - ------------------------------- - (a -- b )∘(c -- d) t[i] == t[k] == u[j] - ^ - - (a -- b t[i])∘(c u[j] -- d) u <= t (u is subtype of t) - ------------------------------- - (a -- b )∘(c -- d) t[i] == u[k] == u[j] - -Let’s work through some examples by hand to develop an intuition for the -algorithm. - -There’s a function in one of the other notebooks. - -:: - - F == pop swap roll< rest rest cons cons - -It’s all “stack chatter” and list manipulation so we should be able to -deduce its type. - -Stack Effect Comments -~~~~~~~~~~~~~~~~~~~~~ - -Joy function types will be represented by Forth-style stack effect -comments. I’m going to use numbers instead of names to keep track of the -stack arguments. (A little bit like `De Bruijn -index `__, at least it -reminds me of them): - -:: - - pop (1 --) - - swap (1 2 -- 2 1) - - roll< (1 2 3 -- 2 3 1) - -These commands alter the stack but don’t “look at” the values so these -numbers represent an “Any type”. - -``pop swap`` -~~~~~~~~~~~~ - -:: - - (1 --) (1 2 -- 2 1) - -Here we encounter a complication. The argument numbers need to be made -unique among both sides. For this let’s change ``pop`` to use 0: - -:: - - (0 --) (1 2 -- 2 1) - -Following the second rule: - -:: - - (1 2 0 -- 2 1) - -``pop∘swap roll<`` -~~~~~~~~~~~~~~~~~~ - -:: - - (1 2 0 -- 2 1) (1 2 3 -- 2 3 1) - -Let’s re-label them: - -:: - - (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b) - -Now we follow the rules. - -We must unify ``1a`` and ``3b``, and ``2a`` and ``2b``, replacing the -terms in the forms: - -:: - - (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b) - w/ {1a: 3b} - (3b 2a 0a -- 2a ) (1b 2b -- 2b 3b 1b) - w/ {2a: 2b} - (3b 2b 0a -- ) (1b -- 2b 3b 1b) - -Here we must apply the second rule: - -:: - - (3b 2b 0a --) (1b -- 2b 3b 1b) - ----------------------------------- - (1b 3b 2b 0a -- 2b 3b 1b) - -Now we de-label the type, uh, labels: - -:: - - (1b 3b 2b 0a -- 2b 3b 1b) - - w/ { - 1b: 1, - 3b: 2, - 2b: 3, - 0a: 0, - } - - (1 2 3 0 -- 3 2 1) - -And now we have the stack effect comment for ``pop∘swap∘roll<``. - -Compiling ``pop∘swap∘roll<`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The simplest way to “compile” this function would be something like: - -.. code:: ipython2 - - def poswrd(s, e, d): - return rolldown(*swap(*pop(s, e, d))) - -However, internally this function would still be allocating tuples -(stack cells) and doing other unnecesssary work. - -Looking ahead for a moment, from the stack effect comment: - -:: - - (1 2 3 0 -- 3 2 1) - -We should be able to directly write out a Python function like: - -.. code:: ipython2 - - def poswrd(stack): - (_, (a, (b, (c, stack)))) = stack - return (c, (b, (a, stack))) - -This eliminates the internal work of the first version. Because this -function only rearranges the stack and doesn’t do any actual processing -on the stack items themselves all the information needed to implement it -is in the stack effect comment. - -Functions on Stacks -~~~~~~~~~~~~~~~~~~~ - -These are slightly tricky. - -:: - - rest ( [1 ...] -- [...] ) - - cons ( 1 [...] -- [1 ...] ) - -``pop∘swap∘roll< rest`` -~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - (1 2 3 0 -- 3 2 1) ([1 ...] -- [...]) - -Re-label (instead of adding left and right tags I’m just taking the next -available index number for the right-side stack effect comment): - -:: - - (1 2 3 0 -- 3 2 1) ([4 ...] -- [...]) - -Unify and update: - -:: - - (1 2 3 0 -- 3 2 1) ([4 ...] -- [...]) - w/ {1: [4 ...]} - ([4 ...] 2 3 0 -- 3 2 ) ( -- [...]) - -Apply the first rule: - -:: - - ([4 ...] 2 3 0 -- 3 2) (-- [...]) - --------------------------------------- - ([4 ...] 2 3 0 -- 3 2 [...]) - -And there we are. - -``pop∘swap∘roll<∘rest rest`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Let’s do it again. - -:: - - ([4 ...] 2 3 0 -- 3 2 [...]) ([1 ...] -- [...]) - -Re-label (the tails of the lists on each side each get their own label): - -:: - - ([4 .0.] 2 3 0 -- 3 2 [.0.]) ([5 .1.] -- [.1.]) - -Unify and update (note the opening square brackets have been omited in -the substitution dict, this is deliberate and I’ll explain below): - -:: - - ([4 .0.] 2 3 0 -- 3 2 [.0.] ) ([5 .1.] -- [.1.]) - w/ { .0.] : 5 .1.] } - ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.]) - -How do we find ``.0.]`` in ``[4 .0.]`` and replace it with ``5 .1.]`` -getting the result ``[4 5 .1.]``? This might seem hard, but because the -underlying structure of the Joy list is a cons-list in Python it’s -actually pretty easy. I’ll explain below. - -Next we unify and find our two terms are the same already: ``[5 .1.]``: - -:: - - ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.]) - -Giving us: - -:: - - ([4 5 .1.] 2 3 0 -- 3 2) (-- [.1.]) - -From here we apply the first rule and get: - -:: - - ([4 5 .1.] 2 3 0 -- 3 2 [.1.]) - -Cleaning up the labels: - -:: - - ([4 5 ...] 2 3 1 -- 3 2 [...]) - -This is the stack effect of ``pop∘swap∘roll<∘rest∘rest``. - -``pop∘swap∘roll<∘rest∘rest cons`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - ([4 5 ...] 2 3 1 -- 3 2 [...]) (1 [...] -- [1 ...]) - -Re-label: - -:: - - ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.]) - -Unify: - -:: - - ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.]) - w/ { .1.] : .2.] } - ([4 5 .2.] 2 3 1 -- 3 2 ) (6 -- [6 .2.]) - w/ {2: 6} - ([4 5 .2.] 6 3 1 -- 3 ) ( -- [6 .2.]) - -First rule: - -:: - - ([4 5 .2.] 6 3 1 -- 3 [6 .2.]) - -Re-label: - -:: - - ([4 5 ...] 2 3 1 -- 3 [2 ...]) - -Done. - -``pop∘swap∘roll<∘rest∘rest∘cons cons`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -One more time. - -:: - - ([4 5 ...] 2 3 1 -- 3 [2 ...]) (1 [...] -- [1 ...]) - -Re-label: - -:: - - ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.]) - -Unify: - -:: - - ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.] ) - w/ { .2.] : 2 .1.] } - ([4 5 .1.] 2 3 1 -- 3 ) (6 -- [6 2 .1.]) - w/ {3: 6} - ([4 5 .1.] 2 6 1 -- ) ( -- [6 2 .1.]) - -First or second rule: - -:: - - ([4 5 .1.] 2 6 1 -- [6 2 .1.]) - -Clean up the labels: - -:: - - ([4 5 ...] 2 3 1 -- [3 2 ...]) - -And there you have it, the stack effect for -``pop∘swap∘roll<∘rest∘rest∘cons∘cons``. - -:: - - ([4 5 ...] 2 3 1 -- [3 2 ...]) - -From this stack effect comment it should be possible to construct the -following Python code: - -.. code:: ipython2 - - def F(stack): - (_, (d, (c, ((a, (b, S0)), stack)))) = stack - return (d, (c, S0)), stack - -Part II: Implementation ------------------------ - -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 - - roll_dn = (1, 2, 3), (2, 3, 1) - - pop = (1,), () - - swap = (1, 2), (2, 1) - -``compose()`` -~~~~~~~~~~~~~ - -.. code:: ipython2 - - def compose(f, g): - - (f_in, f_out), (g_in, g_out) = f, g - - # First rule. - # - # (a -- b) (-- d) - # --------------------- - # (a -- b d) - - if not g_in: - - fg_in, fg_out = f_in, f_out + g_out - - # Second rule. - # - # (a --) (c -- d) - # --------------------- - # (c a -- d) - - elif not f_out: - - fg_in, fg_out = g_in + f_in, g_out - - else: # Unify, update, recur. - - fo, gi = f_out[-1], g_in[-1] - - 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)) - - f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out) - - if s: f_g = update(s, f_g) - - fg_in, fg_out = compose(*f_g) - - return fg_in, fg_out - -``unify()`` -~~~~~~~~~~~ - -.. code:: ipython2 - - 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 - - return s - -``update()`` -~~~~~~~~~~~~ - -.. code:: ipython2 - - def update(s, term): - if not isinstance(term, tuple): - return s.get(term, term) - return tuple(update(s, inner) for inner in term) - -``relabel()`` -~~~~~~~~~~~~~ - -.. code:: ipython2 - - 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) - - relabel(pop, swap) - - - - -.. parsed-literal:: - - (((1,), ()), ((1001, 1002), (1002, 1001))) - - - -``delabel()`` -~~~~~~~~~~~~~ - -.. code:: ipython2 - - 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 - - delabel(relabel(pop, swap)) - - - - -.. parsed-literal:: - - (((0,), ()), ((1, 2), (2, 1))) - - - -``C()`` -~~~~~~~ - -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 - - def C(f, g): - f, g = relabel(f, g) - fg = compose(f, g) - return delabel(fg) - -Let’s try it out. - -.. code:: ipython2 - - C(pop, swap) - - - - -.. parsed-literal:: - - ((1, 2, 0), (2, 1)) - - - -.. code:: ipython2 - - C(C(pop, swap), roll_dn) - - - - -.. parsed-literal:: - - ((3, 1, 2, 0), (2, 1, 3)) - - - -.. code:: ipython2 - - C(swap, roll_dn) - - - - -.. parsed-literal:: - - ((2, 0, 1), (1, 0, 2)) - - - -.. code:: ipython2 - - C(pop, C(swap, roll_dn)) - - - - -.. parsed-literal:: - - ((3, 1, 2, 0), (2, 1, 3)) - - - -.. code:: ipython2 - - poswrd = reduce(C, (pop, swap, roll_dn)) - poswrd - - - - -.. parsed-literal:: - - ((3, 1, 2, 0), (2, 1, 3)) - - - -Stack Functions -~~~~~~~~~~~~~~~ - -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 - - rest = ((1, 2),), (2,) - - cons = (1, 2), ((1, 2),) - -.. code:: ipython2 - - C(poswrd, rest) - - - - -.. parsed-literal:: - - (((3, 4), 1, 2, 0), (2, 1, 4)) - - - -Compare this to the stack effect comment we wrote above: - -:: - - (( (3, 4), 1, 2, 0 ), ( 2, 1, 4 )) - ( [4 ...] 2 3 0 -- 3 2 [...]) - -The translation table, if you will, would be: - -:: - - { - 3: 4, - 4: ...], - 1: 2, - 2: 3, - 0: 0, - } - -.. code:: ipython2 - - F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons)) - - F - - - - -.. parsed-literal:: - - (((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),)) - - - -Compare with the stack effect comment and you can see it works fine: - -:: - - ([4 5 ...] 2 3 1 -- [3 2 ...]) - 3 4 5 1 2 0 2 1 5 - -Dealing with ``cons`` and ``uncons`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -However, if we try to compose e.g. ``cons`` and ``uncons`` it won’t -work: - -.. code:: ipython2 - - uncons = ((1, 2),), (1, 2) - -.. code:: ipython2 - - try: - C(cons, uncons) - except Exception, e: - print e - - -.. parsed-literal:: - - Cannot unify (1, 2) and (1001, 1002). - - -``unify()`` version 2 -^^^^^^^^^^^^^^^^^^^^^ - -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 - - 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 - - elif isinstance(v, int): - s[v] = u - - 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. - - (a, b), (c, d) = u, v - s = unify(a, c, s) - if s != False: - s = unify(b, d, s) - else: - s = False - - return s - -.. code:: ipython2 - - C(cons, uncons) - - - - -.. parsed-literal:: - - ((0, 1), (0, 1)) - - - -Part III: Compiling Yin Functions ---------------------------------- - -Now consider the Python function we would like to derive: - -.. code:: ipython2 - - 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: - -.. code:: ipython2 - - F[0] - - - - -.. parsed-literal:: - - ((3, (4, 5)), 1, 2, 0) - - - -The stack-de-structuring tuple has nearly the same form as our input -stack effect comment tuple, just in the reverse order: - -:: - - (_, (d, (c, ((a, (b, S0)), stack)))) - -Remove the punctuation: - -:: - - _ d c (a, (b, S0)) - -Reverse the order and compare: - -:: - - (a, (b, S0)) c d _ - ((3, (4, 5 )), 1, 2, 0) - -Eh? - -And the return tuple - -.. code:: ipython2 - - F[1] - - - - -.. parsed-literal:: - - ((2, (1, 5)),) - - - -is similar to the output stack effect comment tuple: - -:: - - ((d, (c, S0)), stack) - ((2, (1, 5 )), ) - -This should make it pretty easy to write a Python function that accepts -the stack effect comment tuples and returns a new Python function -(either as a string of code or a function object ready to use) that -performs the semantics of that Joy function (described by the stack -effect.) - -Python Identifiers -~~~~~~~~~~~~~~~~~~ - -We want to substitute Python identifiers for the integers. I’m going to -repurpose ``joy.parser.Symbol`` class for this: - -.. code:: ipython2 - - from collections import defaultdict - from joy.parser import Symbol - - - 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) - -``doc_from_stack_effect()`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -As a convenience I’ve implemented a function to convert the Python stack -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 - - 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) - -``compile_()`` -~~~~~~~~~~~~~~ - -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 - - 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: - -.. code:: ipython2 - - source = compile_('F', F) - - print source - - -.. parsed-literal:: - - def F(stack): - """([3 4 .5.] 1 2 0 -- [2 1 .5.])""" - (a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack - return ((a4, (a3, a2)), stack) - - -Compare: - -.. code:: ipython2 - - def F_python(stack): - (_, (d, (c, ((a, (b, S0)), stack)))) = stack - return ((d, (c, S0)), stack) - -Next steps: - -.. code:: ipython2 - - L = {} - - eval(compile(source, '__main__', 'single'), {}, L) - - L['F'] - - - - -.. parsed-literal:: - - - - - -Let’s try it out: - -.. code:: ipython2 - - from notebook_preamble import D, J, V - from joy.library import SimpleFunctionWrapper - -.. code:: ipython2 - - D['F'] = SimpleFunctionWrapper(L['F']) - -.. code:: ipython2 - - J('[4 5 ...] 2 3 1 F') - - -.. parsed-literal:: - - [3 2 ...] - - -With this, we have a partial Joy compiler that works on the subset of -Joy functions that manipulate stacks (both what I call “stack chatter” -and the ones that manipulate stacks on the stack.) - -I’m probably going to modify the definition wrapper code to detect -definitions that can be compiled by this partial compiler and do it -automatically. It might be a reasonable idea to detect sequences of -compilable functions in definitions that have uncompilable functions in -them and just compile those. However, if your library is well-factored -this might be less helpful. - -Compiling Library Functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We can use ``compile_()`` to generate many primitives in the library -from their stack effect comments: - -.. code:: ipython2 - - def defs(): - - rolldown = (1, 2, 3), (2, 3, 1) - - rollup = (1, 2, 3), (3, 1, 2) - - pop = (1,), () - - swap = (1, 2), (2, 1) - - rest = ((1, 2),), (2,) - - rrest = C(rest, rest) - - cons = (1, 2), ((1, 2),) - - uncons = ((1, 2),), (1, 2) - - swons = C(swap, cons) - - return locals() - -.. code:: ipython2 - - for name, stack_effect_comment in sorted(defs().items()): - print - print compile_(name, stack_effect_comment) - print - - -.. parsed-literal:: - - - def cons(stack): - """(1 2 -- [1 .2.])""" - (a1, (a0, stack)) = stack - return ((a0, a1), stack) - - - def pop(stack): - """(1 --)""" - (a0, stack) = stack - return stack - - - def rest(stack): - """([1 .2.] -- 2)""" - ((a0, a1), stack) = stack - return (a1, stack) - - - def rolldown(stack): - """(1 2 3 -- 2 3 1)""" - (a2, (a1, (a0, stack))) = stack - return (a0, (a2, (a1, stack))) - - - def rollup(stack): - """(1 2 3 -- 3 1 2)""" - (a2, (a1, (a0, stack))) = stack - return (a1, (a0, (a2, stack))) - - - def rrest(stack): - """([0 1 .2.] -- 2)""" - ((a0, (a1, a2)), stack) = stack - return (a2, stack) - - - def swap(stack): - """(1 2 -- 2 1)""" - (a1, (a0, stack)) = stack - return (a0, (a1, stack)) - - - def swons(stack): - """(0 1 -- [1 .0.])""" - (a1, (a0, stack)) = stack - return ((a1, a0), stack) - - - def uncons(stack): - """([1 .2.] -- 1 2)""" - ((a0, a1), stack) = stack - return (a1, (a0, stack)) - - - -Part IV: Types and Subtypes of Arguments ----------------------------------------- - -So far we have dealt with types of functions, those dealing with simple -stack manipulation. Let’s extend our machinery to deal with types of -arguments. - -“Number” Type -~~~~~~~~~~~~~ - -Consider the definition of ``sqr``: - -:: - - sqr == dup mul - -The ``dup`` function accepts one *anything* and returns two of that: - -:: - - dup (1 -- 1 1) - -And ``mul`` accepts two “numbers” (we’re ignoring ints vs. floats -vs. complex, etc., for now) and returns just one: - -:: - - mul (n n -- n) - -So we’re composing: - -:: - - (1 -- 1 1)∘(n n -- n) - -The rules say we unify 1 with ``n``: - -:: - - (1 -- 1 1)∘(n n -- n) - --------------------------- w/ {1: n} - (1 -- 1 )∘(n -- n) - -This involves detecting that “Any type” arguments can accept “numbers”. -If we were composing these functions the other way round this is still -the case: - -:: - - (n n -- n)∘(1 -- 1 1) - --------------------------- w/ {1: n} - (n n -- )∘( -- n n) - -The important thing here is that the mapping is going the same way in -both cases, from the “any” integer to the number - -Distinguishing Numbers -~~~~~~~~~~~~~~~~~~~~~~ - -We should also mind that the number that ``mul`` produces is not -(necessarily) the same as either of its inputs, which are not -(necessarily) the same as each other: - -:: - - mul (n2 n1 -- n3) - - - (1 -- 1 1)∘(n2 n1 -- n3) - -------------------------------- w/ {1: n2} - (n2 -- n2 )∘(n2 -- n3) - - - (n2 n1 -- n3)∘(1 -- 1 1 ) - -------------------------------- w/ {1: n3} - (n2 n1 -- )∘( -- n3 n3) - -Distinguishing Types -~~~~~~~~~~~~~~~~~~~~ - -So we need separate domains of “any” numbers and “number” numbers, and -we need to be able to ask the order of these domains. Now the notes on -the right side of rule three make more sense, eh? - -:: - - (a -- b t[i])∘(c u[j] -- d) t <= u (t is subtype of u) - ------------------------------- - (a -- b )∘(c -- d) t[i] == t[k] == u[j] - ^ - - (a -- b t[i])∘(c u[j] -- d) u <= t (u is subtype of t) - ------------------------------- - (a -- b )∘(c -- d) t[i] == u[k] == u[j] - -The indices ``i``, ``k``, and ``j`` are the number part of our labels -and ``t`` and ``u`` are the domains. - -By creative use of Python’s “double underscore” methods we can define a -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 - - class AnyJoyType(object): - - prefix = 'a' - - def __init__(self, number): - self.number = 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 __ge__(self, other): - return issubclass(other.__class__, self.__class__) - - def __add__(self, other): - return self.__class__(self.number + other) - __radd__ = __add__ - - def __hash__(self): - return hash(repr(self)) - - - class NumberJoyType(AnyJoyType): prefix = 'n' - class FloatJoyType(NumberJoyType): prefix = 'f' - class IntJoyType(FloatJoyType): prefix = 'i' - - - class StackJoyType(AnyJoyType): - prefix = 's' - - - _R = range(10) - A = map(AnyJoyType, _R) - N = map(NumberJoyType, _R) - S = map(StackJoyType, _R) - -Mess with it a little: - -.. code:: ipython2 - - from itertools import permutations - -“Any” types can be specialized to numbers and stacks, but not vice -versa: - -.. code:: ipython2 - - for a, b in permutations((A[0], N[0], S[0]), 2): - print a, '>=', b, '->', a >= b - - -.. parsed-literal:: - - a0 >= n0 -> True - a0 >= s0 -> True - n0 >= a0 -> False - n0 >= s0 -> False - s0 >= a0 -> False - s0 >= n0 -> False - - -Our crude `Numerical -Tower `__ of *numbers* > -*floats* > *integers* works as well (but we’re not going to use it yet): - -.. code:: ipython2 - - for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2): - print a, '>=', b, '->', a >= b - - -.. parsed-literal:: - - a0 >= n0 -> True - a0 >= f0 -> True - a0 >= i0 -> True - n0 >= a0 -> False - n0 >= f0 -> True - n0 >= i0 -> True - f0 >= a0 -> False - f0 >= n0 -> False - f0 >= i0 -> True - i0 >= a0 -> False - i0 >= n0 -> False - i0 >= f0 -> False - - -Typing ``sqr`` -~~~~~~~~~~~~~~ - -.. code:: ipython2 - - dup = (A[1],), (A[1], A[1]) - - mul = (N[1], N[2]), (N[3],) - -.. code:: ipython2 - - dup - - - - -.. parsed-literal:: - - ((a1,), (a1, a1)) - - - -.. code:: ipython2 - - mul - - - - -.. parsed-literal:: - - ((n1, n2), (n3,)) - - - -Modifying the Inferencer -~~~~~~~~~~~~~~~~~~~~~~~~ - -Re-labeling still works fine: - -.. code:: ipython2 - - foo = relabel(dup, mul) - - foo - - - - -.. parsed-literal:: - - (((a1,), (a1, a1)), ((n1001, n1002), (n1003,))) - - - -``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”. - -.. code:: ipython2 - - from collections import 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 - - 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) - -.. code:: ipython2 - - delabel(foo) - - - - -.. parsed-literal:: - - (((a1,), (a1, a1)), ((n1, n2), (n3,))) - - - -``unify()`` version 3 -^^^^^^^^^^^^^^^^^^^^^ - -.. code:: ipython2 - - 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: - -.. code:: ipython2 - - def defs(): - - 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]) - - pop = (A[1],), () - - popop = (A[2], A[1],), () - - popd = (A[2], A[1],), (A[1],) - - popdd = (A[3], A[2], A[1],), (A[2], A[1],) - - swap = (A[1], A[2]), (A[2], A[1]) - - rest = ((A[1], S[1]),), (S[1],) - - rrest = C(rest, rest) - - cons = (A[1], S[1]), ((A[1], S[1]),) - - ccons = C(cons, cons) - - uncons = ((A[1], S[1]),), (A[1], S[1]) - - swons = C(swap, cons) - - dup = (A[1],), (A[1], A[1]) - - dupd = (A[2], A[1]), (A[2], A[2], A[1]) - - mul = (N[1], N[2]), (N[3],) - - sqrt = C(dup, mul) - - first = ((A[1], S[1]),), (A[1],) - - second = C(rest, first) - - third = C(rest, second) - - tuck = (A[2], A[1]), (A[1], A[2], A[1]) - - over = (A[2], A[1]), (A[2], A[1], A[2]) - - succ = pred = (N[1],), (N[2],) - - divmod_ = pm = (N[2], N[1]), (N[4], N[3]) - - return locals() - -.. code:: ipython2 - - DEFS = defs() - -.. code:: ipython2 - - for name, stack_effect_comment in sorted(DEFS.items()): - print name, '=', doc_from_stack_effect(*stack_effect_comment) - - -.. parsed-literal:: - - ccons = (a1 a2 [.1.] -- [a1 a2 .1.]) - cons = (a1 [.1.] -- [a1 .1.]) - divmod_ = (n2 n1 -- n4 n3) - dup = (a1 -- a1 a1) - dupd = (a2 a1 -- a2 a2 a1) - first = ([a1 .1.] -- a1) - mul = (n1 n2 -- n3) - over = (a2 a1 -- a2 a1 a2) - pm = (n2 n1 -- n4 n3) - pop = (a1 --) - popd = (a2 a1 -- a1) - popdd = (a3 a2 a1 -- a2 a1) - popop = (a2 a1 --) - pred = (n1 -- n2) - rest = ([a1 .1.] -- [.1.]) - rolldown = (a1 a2 a3 -- a2 a3 a1) - rollup = (a1 a2 a3 -- a3 a1 a2) - rrest = ([a1 a2 .1.] -- [.1.]) - second = ([a1 a2 .1.] -- a2) - sqrt = (n1 -- n2) - succ = (n1 -- n2) - swap = (a1 a2 -- a2 a1) - swons = ([.1.] a1 -- [a1 .1.]) - third = ([a1 a2 a3 .1.] -- a3) - tuck = (a2 a1 -- a1 a2 a1) - uncons = ([a1 .1.] -- a1 [.1.]) - - -.. code:: ipython2 - - globals().update(DEFS) - -Compose ``dup`` and ``mul`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code:: ipython2 - - C(dup, mul) - - - - -.. parsed-literal:: - - ((n1,), (n2,)) - - - -Revisit the ``F`` function, works fine. - -.. code:: ipython2 - - F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons)) - F - - - - -.. parsed-literal:: - - (((a1, (a2, s1)), a3, a4, a5), ((a4, (a3, s1)),)) - - - -.. code:: ipython2 - - print doc_from_stack_effect(*F) - - -.. parsed-literal:: - - ([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.]) - - -Some otherwise inefficient functions are no longer to be feared. We can -also get the effect of combinators in some limited cases. - -.. code:: ipython2 - - def neato(*funcs): - print doc_from_stack_effect(*reduce(C, funcs)) - -.. code:: ipython2 - - # e.g. [swap] dip - neato(rollup, swap, rolldown) - - -.. parsed-literal:: - - (a1 a2 a3 -- a2 a1 a3) - - -.. code:: ipython2 - - # e.g. [popop] dipd - neato(popdd, rolldown, pop) - - -.. parsed-literal:: - - (a1 a2 a3 a4 -- a3 a4) - - -.. code:: ipython2 - - # Reverse the order of the top three items. - neato(rollup, swap) - - -.. parsed-literal:: - - (a1 a2 a3 -- a3 a2 a1) - - -``compile_()`` version 2 -^^^^^^^^^^^^^^^^^^^^^^^^ - -Because the type labels represent themselves as valid Python identifiers -the ``compile_()`` function doesn’t need to generate them anymore: - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - print compile_('F', F) - - -.. parsed-literal:: - - def F(stack): - """([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.])""" - (a5, (a4, (a3, ((a1, (a2, s1)), stack)))) = stack - return ((a4, (a3, s1)), stack) - - -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 - - print compile_('sqr', C(dup, mul)) - - -.. parsed-literal:: - - def sqr(stack): - """(n1 -- n2)""" - (n1, stack) = stack - return (n2, stack) - - -(Eventually I should come back around to this becuase it’s not tooo -difficult to exend this code to be able to compile e.g. -``n2 = mul(n1, n1)`` for ``mul`` with the right variable names and -insert it in the right place. It requires a little more support from the -library functions, in that we need to know to call ``mul()`` the Python -function for ``mul`` the Joy function, but since *most* of the math -functions (at least) are already wrappers it should be straightforward.) - -``compilable()`` -^^^^^^^^^^^^^^^^ - -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 - - from itertools import imap - - - def compilable(f): - return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f) - -.. code:: ipython2 - - for name, stack_effect_comment in sorted(defs().items()): - if compilable(stack_effect_comment): - print name, '=', doc_from_stack_effect(*stack_effect_comment) - - -.. parsed-literal:: - - ccons = (a1 a2 [.1.] -- [a1 a2 .1.]) - cons = (a1 [.1.] -- [a1 .1.]) - dup = (a1 -- a1 a1) - dupd = (a2 a1 -- a2 a2 a1) - first = ([a1 .1.] -- a1) - over = (a2 a1 -- a2 a1 a2) - pop = (a1 --) - popd = (a2 a1 -- a1) - popdd = (a3 a2 a1 -- a2 a1) - popop = (a2 a1 --) - rest = ([a1 .1.] -- [.1.]) - rolldown = (a1 a2 a3 -- a2 a3 a1) - rollup = (a1 a2 a3 -- a3 a1 a2) - rrest = ([a1 a2 .1.] -- [.1.]) - second = ([a1 a2 .1.] -- a2) - swap = (a1 a2 -- a2 a1) - swons = ([.1.] a1 -- [a1 .1.]) - third = ([a1 a2 a3 .1.] -- a3) - tuck = (a2 a1 -- a1 a2 a1) - uncons = ([a1 .1.] -- a1 [.1.]) - - -Part V: Functions that use the Stack ------------------------------------- - -Consider the ``stack`` function which grabs the whole stack, quotes it, -and puts it on itself: - -:: - - stack (... -- ... [...] ) - stack (... a -- ... a [a ...] ) - stack (... b a -- ... b a [a b ...]) - -We would like to represent this in Python somehow. To do this we use a -simple, elegant trick. - -:: - - stack S -- ( S, S) - stack (a, S) -- ( (a, S), (a, S)) - stack (a, (b, S)) -- ( (a, (b, S)), (a, (b, S))) - -Instead of representing the stack effect comments as a single tuple -(with N items in it) we use the same cons-list structure to hold the -sequence and ``unify()`` the whole comments. - -``stack∘uncons`` -~~~~~~~~~~~~~~~~ - -Let’s try composing ``stack`` and ``uncons``. We want this result: - -:: - - stack∘uncons (... a -- ... a a [...]) - -The stack effects are: - -:: - - stack = S -- (S, S) - - uncons = ((a, Z), S) -- (Z, (a, S)) - -Unifying: - -:: - - S -- (S, S) ∘ ((a, Z), S) -- (Z, (a, S )) - w/ { S: (a, Z) } - (a, Z) -- ∘ -- (Z, (a, (a, Z))) - -So: - -:: - - stack∘uncons == (a, Z) -- (Z, (a, (a, Z))) - -It works. - -``stack∘uncons∘uncons`` -~~~~~~~~~~~~~~~~~~~~~~~ - -Let’s try ``stack∘uncons∘uncons``: - -:: - - (a, S ) -- (S, (a, (a, S ))) ∘ ((b, Z), S` ) -- (Z, (b, S` )) - - w/ { S: (b, Z) } - - (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), S` ) -- (Z, (b, S` )) - - w/ { S`: (a, (a, (b, Z))) } - - (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), (a, (a, (b, Z)))) -- (Z, (b, (a, (a, (b, Z))))) - - (a, (b, Z)) -- (Z, (b, (a, (a, (b, Z))))) - -It works. - -``compose()`` version 2 -^^^^^^^^^^^^^^^^^^^^^^^ - -This function has to be modified to use the new datastructures and it is -no longer recursive, instead recursion happens as part of unification. -Further, the first and second of Pöial’s rules are now handled -automatically by the unification algorithm. (One easy way to see this is -that now an empty stack effect comment is represented by a -``StackJoyType`` instance which is not “falsey” and so neither of the -first two rules’ ``if`` clauses will ever be ``True``. Later on I change -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 - - 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. - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - C(stack, uncons) - - - - -.. parsed-literal:: - - ((a1, s1), (s1, (a1, (a1, s1)))) - - - -.. code:: ipython2 - - reduce(C, (stack, uncons, uncons)) - - - - -.. parsed-literal:: - - ((a1, (a2, s1)), (s1, (a2, (a1, (a1, (a2, s1)))))) - - - -The display function should be changed too. - -``doc_from_stack_effect()`` version 2 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Clunky junk, but it will suffice for now. - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - for name, stack_effect_comment in sorted(NEW_DEFS.items()): - print name, '=', doc_from_stack_effect(*stack_effect_comment) - - -.. parsed-literal:: - - ccons = (a1 a2 [.1.] -- [a1 a2 .1.]) - cons = (a1 [.1.] -- [a1 .1.]) - divmod_ = (n2 n1 -- n4 n3) - dup = (a1 -- a1 a1) - dupd = (a2 a1 -- a2 a2 a1) - first = ([a1 .1.] -- a1) - mul = (n1 n2 -- n3) - over = (a2 a1 -- a2 a1 a2) - pm = (n2 n1 -- n4 n3) - pop = (a1 --) - popd = (a2 a1 -- a1) - popdd = (a3 a2 a1 -- a2 a1) - popop = (a2 a1 --) - pred = (n1 -- n2) - rest = ([a1 .1.] -- [.1.]) - rolldown = (a1 a2 a3 -- a2 a3 a1) - rollup = (a1 a2 a3 -- a3 a1 a2) - rrest = ([a1 a2 .1.] -- [.1.]) - second = ([a1 a2 .1.] -- a2) - sqrt = (n1 -- n2) - stack = (... -- ... [...]) - succ = (n1 -- n2) - swaack = ([.1.] -- [.0.]) - swap = (a1 a2 -- a2 a1) - swons = ([.1.] a1 -- [a1 .1.]) - third = ([a1 a2 a3 .1.] -- a3) - tuck = (a2 a1 -- a1 a2 a1) - uncons = ([a1 .1.] -- a1 [.1.]) - - -.. code:: ipython2 - - 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))) - - -.. parsed-literal:: - - - (... -- ... [...]) - - (... a1 -- ... a1 a1 [...]) - - (... a2 a1 -- ... a2 a1 a1 a2 [...]) - - (... a1 -- ... a1 [a1 ...]) - - -.. code:: ipython2 - - print doc_from_stack_effect(*C(ccons, stack)) - - -.. parsed-literal:: - - (... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...]) - - -.. code:: ipython2 - - Q = C(ccons, stack) - - Q - - - - -.. parsed-literal:: - - ((s1, (a1, (a2, s2))), (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2))) - - - -``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: - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - print compile_('Q', Q) - - -.. parsed-literal:: - - def Q(stack): - """(... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])""" - (s1, (a1, (a2, s2))) = stack - return (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2)) - - - - - - - -.. code:: ipython2 - - unstack = (S[1], S[0]), S[1] - enstacken = S[0], (S[0], S[1]) - -.. code:: ipython2 - - print doc_from_stack_effect(*unstack) - - -.. parsed-literal:: - - ([.1.] --) - - -.. code:: ipython2 - - print doc_from_stack_effect(*enstacken) - - -.. parsed-literal:: - - (-- [.0.]) - - -.. code:: ipython2 - - print doc_from_stack_effect(*C(cons, unstack)) - - -.. parsed-literal:: - - (a1 [.1.] -- a1) - - -.. code:: ipython2 - - print doc_from_stack_effect(*C(cons, enstacken)) - - -.. parsed-literal:: - - (a1 [.1.] -- [[a1 .1.] .2.]) - - -.. code:: ipython2 - - C(cons, unstack) - - - - -.. parsed-literal:: - - ((s1, (a1, s2)), (a1, s1)) - - - - -Part VI: Multiple Stack Effects -------------------------------- - -… - -.. code:: ipython2 - - class IntJoyType(NumberJoyType): prefix = 'i' - - - F = map(FloatJoyType, _R) - I = map(IntJoyType, _R) - -.. code:: ipython2 - - 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])), - ] - -.. code:: ipython2 - - for f in muls: - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (i1 i2 -- i3) - (i1 f2 -- f3) - (f1 i2 -- f3) - (f1 f2 -- f3) - - -.. code:: ipython2 - - 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) - - -.. parsed-literal:: - - (a1 -- a1 a1) (i1 i2 -- i3) (i1 -- i2) - (a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2) - - -.. code:: ipython2 - - 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 MC(F, G): - return sorted(set(meta_compose(F, G))) - -.. code:: ipython2 - - for f in MC([dup], [mul]): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (n1 -- n2) - - -.. code:: ipython2 - - for f in MC([dup], muls): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (f1 -- f2) - (i1 -- i2) - - -Representing an Unbounded Sequence of Types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We can borrow a trick from `Brzozowski’s Derivatives of Regular -Expressions `__ to -invent a new type of type variable, a “sequence type” (I think this is -what they mean in the literature by that term…) or “`Kleene -Star `__” type. I’m going to -represent it as a type letter and the asterix, so a sequence of zero or -more ``AnyJoyType`` variables would be: - -:: - - A* - -The ``A*`` works by splitting the universe into two alternate histories: - -:: - - A* -> 0 | A A* - -The Kleene star variable disappears in one universe, and in the other it -turns into an ``AnyJoyType`` variable followed by itself again. We have -to return all universes (represented by their substitution dicts, the -“unifiers”) that don’t lead to type conflicts. - -Consider unifying two stacks (the lowercase letters are any type -variables of the kinds we have defined so far): - -:: - - [a A* b .0.] U [c d .1.] - w/ {c: a} - [ A* b .0.] U [ d .1.] - -Now we have to split universes to unify ``A*``. In the first universe it -disappears: - -:: - - [b .0.] U [d .1.] - w/ {d: b, .1.: .0.} - [] U [] - -While in the second it spawns an ``A``, which we will label ``e``: - -:: - - [e A* b .0.] U [d .1.] - w/ {d: e} - [ A* b .0.] U [ .1.] - w/ {.1.: A* b .0.} - [ A* b .0.] U [ A* b .0.] - -Giving us two unifiers: - -:: - - {c: a, d: b, .1.: .0.} - {c: a, d: e, .1.: A* b .0.} - -.. code:: ipython2 - - class KleeneStar(object): - - kind = AnyJoyType - - 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 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 __ge__(self, other): - return self.kind >= other.kind - - def __add__(self, other): - return self.__class__(self.number + other) - __radd__ = __add__ - - 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 - - - As = map(AnyStarJoyType, _R) - Ns = map(NumberStarJoyType, _R) - Ss = map(StackStarJoyType, _R) - -``unify()`` version 4 -^^^^^^^^^^^^^^^^^^^^^ - -Can now return multiple results… - -.. code:: ipython2 - - 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} - -.. code:: ipython2 - - a = (As[1], S[1]) - a - - - - -.. parsed-literal:: - - (a1*, s1) - - - -.. code:: ipython2 - - b = (A[1], S[2]) - b - - - - -.. parsed-literal:: - - (a1, s2) - - - -.. code:: ipython2 - - for result in unify(b, a): - print result, '->', update(result, a), update(result, b) - - -.. parsed-literal:: - - {s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2) - {a1: a10001, s2: (a1*, s1)} -> (a1*, s1) (a10001, (a1*, s1)) - - -.. code:: ipython2 - - for result in unify(a, b): - print result, '->', update(result, a), update(result, b) - - -.. parsed-literal:: - - {s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2) - {a1: a10002, s2: (a1*, s1)} -> (a1*, s1) (a10002, (a1*, s1)) - - -:: - - (a1*, s1) [a1*] (a1, s2) [a1] - - (a1*, (a1, s2)) [a1* a1] (a1, s2) [a1] - - (a1*, s1) [a1*] (a2, (a1*, s1)) [a2 a1*] - -.. code:: ipython2 - - sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0]) - - print doc_from_stack_effect(*sum_) - - -.. parsed-literal:: - - ([n1* .1.] -- n0) - - -.. code:: ipython2 - - f = (N[1], (N[2], (N[3], S[1]))), S[0] - - print doc_from_stack_effect(S[0], f) - - -.. parsed-literal:: - - (-- [n1 n2 n3 .1.]) - - -.. code:: ipython2 - - for result in unify(sum_[0], f): - print result, '->', update(result, sum_[1]) - - -.. parsed-literal:: - - {s1: (n1, (n2, (n3, s1)))} -> (n0, s0) - {n1: n10001, s1: (n2, (n3, s1))} -> (n0, s0) - {n1: n10001, s1: (n3, s1), n2: n10002} -> (n0, s0) - {n1: n10001, s1: (n1*, s1), n3: n10003, n2: n10002} -> (n0, s0) - - -``compose()`` version 3 -^^^^^^^^^^^^^^^^^^^^^^^ - -This function has to be modified to yield multiple results. - -.. code:: ipython2 - - 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)) - - - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - for f in MC([dup], muls): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (f1 -- f2) - (i1 -- i2) - - -.. code:: ipython2 - - - - for f in MC([dup], [sum_]): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - ([n1* .1.] -- [n1* .1.] n1) - - -.. code:: ipython2 - - - - for f in MC([cons], [sum_]): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (a1 [.1.] -- n1) - (n1 [n1* .1.] -- n2) - - -.. code:: ipython2 - - 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) - - -.. parsed-literal:: - - (a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n1 [n1* .1.] -- n2) - - -.. code:: ipython2 - - a = (A[4], (As[1], (A[3], S[1]))) - a - - - - -.. parsed-literal:: - - (a4, (a1*, (a3, s1))) - - - -.. code:: ipython2 - - b = (A[1], (A[2], S[2])) - b - - - - -.. parsed-literal:: - - (a1, (a2, s2)) - - - -.. code:: ipython2 - - for result in unify(b, a): - print result - - -.. parsed-literal:: - - {a1: a4, s2: s1, a2: a3} - {a1: a4, s2: (a1*, (a3, s1)), a2: a10003} - - -.. code:: ipython2 - - for result in unify(a, b): - print result - - -.. parsed-literal:: - - {s2: s1, a2: a3, a4: a1} - {s2: (a1*, (a3, s1)), a2: a10004, a4: a1} - - -Part VII: Typing Combinators ----------------------------- - -In order to compute the stack effect of combinators you kinda have to -have the quoted programs they expect available. In the most general -case, the ``i`` combinator, you can’t say anything about its stack -effect other than it expects one quote: - -:: - - i (... [.1.] -- ... .1.) - -Or - -:: - - i (... [A* .1.] -- ... A*) - -Consider the type of: - -:: - - [cons] dip - -Obviously it would be: - -:: - - (a1 [..1] a2 -- [a1 ..1] a2) - -``dip`` itself could have: - -:: - - (a1 [..1] -- ... then what? - -Without any information about the contents of the quote we can’t say -much about the result. - -Hybrid Inferencer/Interpreter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -I think there’s a way forward. If we convert our list (of terms we are -composing) into a stack structure we can use it as a *Joy expression*, -then we can treat the *output half* of a function’s stack effect comment -as a Joy interpreter stack, and just execute combinators directly. We -can hybridize the compostition function with an interpreter to evaluate -combinators, compose non-combinator functions, and put type variables on -the stack. For combinators like ``branch`` that can have more than one -stack effect we have to “split universes” again and return both. - -Joy Types for Functions -^^^^^^^^^^^^^^^^^^^^^^^ - -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 - - class FunctionJoyType(AnyJoyType): - - 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 __repr__(self): - return self.name - -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 - - class SymbolJoyType(FunctionJoyType): - prefix = 'F' - -For combinators the list contains Python functions. - -.. code:: ipython2 - - class CombinatorJoyType(FunctionJoyType): - - prefix = 'C' - - 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] - -For simple combinators that have only one effect (like ``dip``) you only -need one function and it can be the combinator itself. - -.. code:: ipython2 - - import joy.library - - 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. - -.. code:: ipython2 - - 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 - - branch = CombinatorJoyType('branch', [branch_true, branch_false], 100) - -You can also provide an optional stack effect, input-side only, that -will then be used as an identity function (that accepts and returns -stacks that match the “guard” stack effect) which will be used to guard -against type mismatches going into the evaluation of the combinator. - -``infer()`` -^^^^^^^^^^^ - -With those in place, we can define a function that accepts a sequence of -Joy type variables, including ones representing functions (not just -values), and attempts to grind out all the possible stack effects of -that expression. - -One tricky thing is that type variables *in the expression* have to be -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 - - ID = S[0], S[0] # Identity function. - - - 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] - - 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) - - 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) - - else: - fi, fo = F - res = _infer(e, (fi, (n, fo))) - - 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 _log_it(e, F): - _log.info( - u'%3i %s ∘ %s', - len(inspect_stack()), - doc_from_stack_effect(*F), - expression_to_string(e), - ) - -Work in Progress -^^^^^^^^^^^^^^^^ - -And that brings us to current Work-In-Progress. The mixed-mode -inferencer/interpreter ``infer()`` function seems to work well. There -are details I should document, and the rest of the code in the ``types`` -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 : - -.. code:: ipython2 - - 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) - - globals().update(FUNCTIONS) - - h = infer((pred, s2), (mul, s3), (div, s4), (nullary, (bool, s5)), dipd, branch) - - print '-' * 40 - - for fi, fo in h: - print doc_from_stack_effect(fi, fo) - - -:: - - - --------------------------------------------------------------------------- - - ZeroDivisionError Traceback (most recent call last) - - in () - ----> 1 1/0 # (Don't try to run this cell! It's not going to work. This is "read only" code heh..) - 2 - 3 logging.basicConfig(format='%(message)s', stream=sys.stdout, level=logging.INFO) - 4 - 5 globals().update(FUNCTIONS) - - - ZeroDivisionError: integer division or modulo by zero - - -The numbers at the start of the lines are the current depth of the -Python call stack. They’re followed by the current computed stack effect -(initialized to ``ID``) then the pending expression (the inference of -the stack effect of which is the whole object of the current example.) - -In this example we are implementing (and inferring) ``ifte`` as -``[nullary bool] dipd branch`` which shows off a lot of the current -implementation in action. - -:: - - 7 (--) ∘ [pred] [mul] [div] [nullary bool] dipd branch - 8 (-- [pred ...2]) ∘ [mul] [div] [nullary bool] dipd branch - 9 (-- [pred ...2] [mul ...3]) ∘ [div] [nullary bool] dipd branch - 10 (-- [pred ...2] [mul ...3] [div ...4]) ∘ [nullary bool] dipd branch - 11 (-- [pred ...2] [mul ...3] [div ...4] [nullary bool ...5]) ∘ dipd branch - 15 (-- [pred ...5]) ∘ nullary bool [mul] [div] branch - 19 (-- [pred ...2]) ∘ [stack] dinfrirst bool [mul] [div] branch - 20 (-- [pred ...2] [stack ]) ∘ dinfrirst bool [mul] [div] branch - 22 (-- [pred ...2] [stack ]) ∘ dip infra first bool [mul] [div] branch - 26 (--) ∘ stack [pred] infra first bool [mul] [div] branch - 29 (... -- ... [...]) ∘ [pred] infra first bool [mul] [div] branch - 30 (... -- ... [...] [pred ...1]) ∘ infra first bool [mul] [div] branch - 34 (--) ∘ pred s1 swaack first bool [mul] [div] branch - 37 (n1 -- n2) ∘ [n1] swaack first bool [mul] [div] branch - 38 (... n1 -- ... n2 [n1 ...]) ∘ swaack first bool [mul] [div] branch - 41 (... n1 -- ... n1 [n2 ...]) ∘ first bool [mul] [div] branch - 44 (n1 -- n1 n2) ∘ bool [mul] [div] branch - 47 (n1 -- n1 b1) ∘ [mul] [div] branch - 48 (n1 -- n1 b1 [mul ...1]) ∘ [div] branch - 49 (n1 -- n1 b1 [mul ...1] [div ...2]) ∘ branch - 53 (n1 -- n1) ∘ div - 56 (f2 f1 -- f3) ∘ - 56 (i1 f1 -- f2) ∘ - 56 (f1 i1 -- f2) ∘ - 56 (i2 i1 -- f1) ∘ - 53 (n1 -- n1) ∘ mul - 56 (f2 f1 -- f3) ∘ - 56 (i1 f1 -- f2) ∘ - 56 (f1 i1 -- f2) ∘ - 56 (i2 i1 -- i3) ∘ - ---------------------------------------- - (f2 f1 -- f3) - (i1 f1 -- f2) - (f1 i1 -- f2) - (i2 i1 -- f1) - (i2 i1 -- i3) - -Conclusion ----------- - -We built a simple type inferencer, and a kind of crude “compiler” for a -subset of Joy functions. Then we built a more powerful inferencer that -actually does some evaluation and explores branching code paths - -Work remains to be done: - -- the rest of the library has to be covered -- figure out how to deal with ``loop`` and ``genrec``, etc.. -- extend the types to check values (see the appendix) -- other kinds of “higher order” type variables, OR, AND, etc.. -- maybe rewrite in Prolog for great good? -- definitions - - - don’t permit composition of functions that don’t compose - - auto-compile compilable functions - -- Compiling more than just the Yin functions. -- getting better visibility (than Python debugger.) -- DOOOOCS!!!! Lots of docs! - - - docstrings all around - - improve this notebook (it kinda falls apart at the end - narratively. I went off and just started writing code to see if it - would work. It does, but now I have to come back and describe here - what I did. - -Appendix: Joy in the Logical Paradigm -------------------------------------- - -For *type checking* to work the type label classes have to be modified -to let ``T >= t`` succeed, where e.g. ``T`` is ``IntJoyType`` and ``t`` -is ``int``. If you do that you can take advantage of the *logical -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. - -.. code:: ipython2 - - 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/_sources/notebooks/Zipper.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt deleted file mode 100644 index dc4f996..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/Zipper.rst.txt +++ /dev/null @@ -1,352 +0,0 @@ -Traversing Datastructures with Zippers -====================================== - -This notebook is about using the “zipper” with joy datastructures. See -the `Zipper wikipedia -entry `__ or -the original paper: `“FUNCTIONAL PEARL The Zipper” by Gérard -Huet `__ - -Given a datastructure on the stack we can navigate through it, modify -it, and rebuild it using the “zipper” technique. - -.. code:: ipython2 - - from notebook_preamble import J, V, define - -Trees ------ - -In Joypy there aren’t any complex datastructures, just ints, floats, -strings, Symbols (strings that are names of functions) and sequences -(aka lists, aka quoted literals, aka aggregates, etc…), but we can build -`trees `__ out -of sequences. - -.. code:: ipython2 - - J('[1 [2 [3 4 25 6] 7] 8]') - - -.. parsed-literal:: - - [1 [2 [3 4 25 6] 7] 8] - - -Zipper in Joy -------------- - -Zippers work by keeping track of the current item, the already-seen -items, and the yet-to-be seen items as you traverse a datastructure (the -datastructure used to keep track of these items is the zipper.) - -In Joy we can do this with the following words: - -:: - - z-down == [] swap uncons swap - z-up == swons swap shunt - z-right == [swons] cons dip uncons swap - z-left == swons [uncons swap] dip swap - -Let’s use them to change 25 into 625. The first time a word is used I -show the trace so you can see how it works. If we were going to use -these a lot it would make sense to write Python versions for efficiency, -but see below. - -.. code:: ipython2 - - define('z-down == [] swap uncons swap') - define('z-up == swons swap shunt') - define('z-right == [swons] cons dip uncons swap') - define('z-left == swons [uncons swap] dip swap') - -.. code:: ipython2 - - V('[1 [2 [3 4 25 6] 7] 8] z-down') - - -.. parsed-literal:: - - . [1 [2 [3 4 25 6] 7] 8] z-down - [1 [2 [3 4 25 6] 7] 8] . z-down - [1 [2 [3 4 25 6] 7] 8] . [] swap uncons swap - [1 [2 [3 4 25 6] 7] 8] [] . swap uncons swap - [] [1 [2 [3 4 25 6] 7] 8] . uncons swap - [] 1 [[2 [3 4 25 6] 7] 8] . swap - [] [[2 [3 4 25 6] 7] 8] 1 . - - -.. code:: ipython2 - - V('[] [[2 [3 4 25 6] 7] 8] 1 z-right') - - -.. parsed-literal:: - - . [] [[2 [3 4 25 6] 7] 8] 1 z-right - [] . [[2 [3 4 25 6] 7] 8] 1 z-right - [] [[2 [3 4 25 6] 7] 8] . 1 z-right - [] [[2 [3 4 25 6] 7] 8] 1 . z-right - [] [[2 [3 4 25 6] 7] 8] 1 . [swons] cons dip uncons swap - [] [[2 [3 4 25 6] 7] 8] 1 [swons] . cons dip uncons swap - [] [[2 [3 4 25 6] 7] 8] [1 swons] . dip uncons swap - [] . 1 swons [[2 [3 4 25 6] 7] 8] uncons swap - [] 1 . swons [[2 [3 4 25 6] 7] 8] uncons swap - [] 1 . swap cons [[2 [3 4 25 6] 7] 8] uncons swap - 1 [] . cons [[2 [3 4 25 6] 7] 8] uncons swap - [1] . [[2 [3 4 25 6] 7] 8] uncons swap - [1] [[2 [3 4 25 6] 7] 8] . uncons swap - [1] [2 [3 4 25 6] 7] [8] . swap - [1] [8] [2 [3 4 25 6] 7] . - - -.. code:: ipython2 - - J('[1] [8] [2 [3 4 25 6] 7] z-down') - - -.. parsed-literal:: - - [1] [8] [] [[3 4 25 6] 7] 2 - - -.. code:: ipython2 - - J('[1] [8] [] [[3 4 25 6] 7] 2 z-right') - - -.. parsed-literal:: - - [1] [8] [2] [7] [3 4 25 6] - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [3 4 25 6] z-down') - - -.. parsed-literal:: - - [1] [8] [2] [7] [] [4 25 6] 3 - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [] [4 25 6] 3 z-right') - - -.. parsed-literal:: - - [1] [8] [2] [7] [3] [25 6] 4 - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [3] [25 6] 4 z-right') - - -.. parsed-literal:: - - [1] [8] [2] [7] [4 3] [6] 25 - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [4 3] [6] 25 sqr') - - -.. parsed-literal:: - - [1] [8] [2] [7] [4 3] [6] 625 - - -.. code:: ipython2 - - V('[1] [8] [2] [7] [4 3] [6] 625 z-up') - - -.. parsed-literal:: - - . [1] [8] [2] [7] [4 3] [6] 625 z-up - [1] . [8] [2] [7] [4 3] [6] 625 z-up - [1] [8] . [2] [7] [4 3] [6] 625 z-up - [1] [8] [2] . [7] [4 3] [6] 625 z-up - [1] [8] [2] [7] . [4 3] [6] 625 z-up - [1] [8] [2] [7] [4 3] . [6] 625 z-up - [1] [8] [2] [7] [4 3] [6] . 625 z-up - [1] [8] [2] [7] [4 3] [6] 625 . z-up - [1] [8] [2] [7] [4 3] [6] 625 . swons swap shunt - [1] [8] [2] [7] [4 3] [6] 625 . swap cons swap shunt - [1] [8] [2] [7] [4 3] 625 [6] . cons swap shunt - [1] [8] [2] [7] [4 3] [625 6] . swap shunt - [1] [8] [2] [7] [625 6] [4 3] . shunt - [1] [8] [2] [7] [3 4 625 6] . - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [3 4 625 6] z-up') - - -.. parsed-literal:: - - [1] [8] [2 [3 4 625 6] 7] - - -.. code:: ipython2 - - J('[1] [8] [2 [3 4 625 6] 7] z-up') - - -.. parsed-literal:: - - [1 [2 [3 4 625 6] 7] 8] - - -``dip`` and ``infra`` ---------------------- - -In Joy we have the ``dip`` and ``infra`` combinators which can “target” -or “address” any particular item in a Joy tree structure. - -.. code:: ipython2 - - V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra') - - -.. parsed-literal:: - - . [1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra - [1 [2 [3 4 25 6] 7] 8] . [[[[[[sqr] dipd] infra] dip] infra] dip] infra - [1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] . infra - 8 [2 [3 4 25 6] 7] 1 . [[[[[sqr] dipd] infra] dip] infra] dip [] swaack - 8 [2 [3 4 25 6] 7] 1 [[[[[sqr] dipd] infra] dip] infra] . dip [] swaack - 8 [2 [3 4 25 6] 7] . [[[[sqr] dipd] infra] dip] infra 1 [] swaack - 8 [2 [3 4 25 6] 7] [[[[sqr] dipd] infra] dip] . infra 1 [] swaack - 7 [3 4 25 6] 2 . [[[sqr] dipd] infra] dip [8] swaack 1 [] swaack - 7 [3 4 25 6] 2 [[[sqr] dipd] infra] . dip [8] swaack 1 [] swaack - 7 [3 4 25 6] . [[sqr] dipd] infra 2 [8] swaack 1 [] swaack - 7 [3 4 25 6] [[sqr] dipd] . infra 2 [8] swaack 1 [] swaack - 6 25 4 3 . [sqr] dipd [7] swaack 2 [8] swaack 1 [] swaack - 6 25 4 3 [sqr] . dipd [7] swaack 2 [8] swaack 1 [] swaack - 6 25 . sqr 4 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 25 . dup mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 25 25 . mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 625 . 4 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 625 4 . 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 625 4 3 . [7] swaack 2 [8] swaack 1 [] swaack - 6 625 4 3 [7] . swaack 2 [8] swaack 1 [] swaack - 7 [3 4 625 6] . 2 [8] swaack 1 [] swaack - 7 [3 4 625 6] 2 . [8] swaack 1 [] swaack - 7 [3 4 625 6] 2 [8] . swaack 1 [] swaack - 8 [2 [3 4 625 6] 7] . 1 [] swaack - 8 [2 [3 4 625 6] 7] 1 . [] swaack - 8 [2 [3 4 625 6] 7] 1 [] . swaack - [1 [2 [3 4 625 6] 7] 8] . - - -If you read the trace carefully you’ll see that about half of it is the -``dip`` and ``infra`` combinators de-quoting programs and “digging” into -the subject datastructure. Instead of maintaining temporary results on -the stack they are pushed into the pending expression (continuation). -When ``sqr`` has run the rest of the pending expression rebuilds the -datastructure. - -``Z`` ------ - -Imagine a function ``Z`` that accepts a sequence of ``dip`` and -``infra`` combinators, a quoted program ``[Q]``, and a datastructure to -work on. It would effectively execute the quoted program as if it had -been embedded in a nested series of quoted programs, e.g.: - -:: - - [...] [Q] [dip dip infra dip infra dip infra] Z - ------------------------------------------------------------- - [...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra - - -The ``Z`` function isn’t hard to make. - -.. code:: ipython2 - - define('Z == [[] cons cons] step i') - -Here it is in action in a simplified scenario. - -.. code:: ipython2 - - V('1 [2 3 4] Z') - - -.. parsed-literal:: - - . 1 [2 3 4] Z - 1 . [2 3 4] Z - 1 [2 3 4] . Z - 1 [2 3 4] . [[] cons cons] step i - 1 [2 3 4] [[] cons cons] . step i - 1 2 [[] cons cons] . i [3 4] [[] cons cons] step i - 1 2 . [] cons cons [3 4] [[] cons cons] step i - 1 2 [] . cons cons [3 4] [[] cons cons] step i - 1 [2] . cons [3 4] [[] cons cons] step i - [1 2] . [3 4] [[] cons cons] step i - [1 2] [3 4] . [[] cons cons] step i - [1 2] [3 4] [[] cons cons] . step i - [1 2] 3 [[] cons cons] . i [4] [[] cons cons] step i - [1 2] 3 . [] cons cons [4] [[] cons cons] step i - [1 2] 3 [] . cons cons [4] [[] cons cons] step i - [1 2] [3] . cons [4] [[] cons cons] step i - [[1 2] 3] . [4] [[] cons cons] step i - [[1 2] 3] [4] . [[] cons cons] step i - [[1 2] 3] [4] [[] cons cons] . step i - [[1 2] 3] 4 [[] cons cons] . i i - [[1 2] 3] 4 . [] cons cons i - [[1 2] 3] 4 [] . cons cons i - [[1 2] 3] [4] . cons i - [[[1 2] 3] 4] . i - . [[1 2] 3] 4 - [[1 2] 3] . 4 - [[1 2] 3] 4 . - - -And here it is doing the main thing. - -.. code:: ipython2 - - J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z') - - -.. parsed-literal:: - - [1 [2 [3 4 625 6] 7] 8] - - -Addressing ----------- - -Because we are only using two combinators we could replace the list with -a string made from only two characters. - -:: - - [...] [Q] 'ddididi' Zstr - ------------------------------------------------------------- - [...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra - -The string can be considered a name or address for an item in the -subject datastructure. - -Determining the right “path” for an item in a tree. ---------------------------------------------------- - -It’s easy to read off (in reverse) the right sequence of “d” and “i” -from the subject datastructure: - -:: - - [ n [ n [ n n x ... - i d i d i d d Bingo! - diff --git a/docs/sphinx_docs/_build/html/_sources/notebooks/index.rst.txt b/docs/sphinx_docs/_build/html/_sources/notebooks/index.rst.txt deleted file mode 100644 index dbb23a5..0000000 --- a/docs/sphinx_docs/_build/html/_sources/notebooks/index.rst.txt +++ /dev/null @@ -1,27 +0,0 @@ - -Essays about Programming in Joy -=============================== - -These essays are adapted from Jupyter notebooks. I hope to have those hosted somewhere where people can view them "live" and interact with them, possibly on MS Azure. For now, Sphinx does such a great job rendering the HTML that I am copying over some notebooks in ReST format and hand-editing them into these documents. - -.. toctree:: - :glob: - :maxdepth: 2 - - Developing - Quadratic - Replacing - Recursion_Combinators - Ordered_Binary_Trees - Treestep - Generator_Programs - Newton-Raphson - Square_Spiral - Zipper - Types - TypeChecking - NoUpdates - Categorical - The_Four_Operations - Derivatives_of_Regular_Expressions - diff --git a/docs/sphinx_docs/_build/html/_sources/parser.rst.txt b/docs/sphinx_docs/_build/html/_sources/parser.rst.txt deleted file mode 100644 index 2306582..0000000 --- a/docs/sphinx_docs/_build/html/_sources/parser.rst.txt +++ /dev/null @@ -1,20 +0,0 @@ - -Parsing Text into Joy Expressions -================================= - -TODO: example... - - -``joy.parser`` ---------------- - - -.. automodule:: joy.parser - :members: - - -Parser Internals ----------------- - -TODO: Document things like the regular expressions used for tokenizing, and the re.Scanner, etc... - diff --git a/docs/sphinx_docs/_build/html/_sources/pretty.rst.txt b/docs/sphinx_docs/_build/html/_sources/pretty.rst.txt deleted file mode 100644 index 866588c..0000000 --- a/docs/sphinx_docs/_build/html/_sources/pretty.rst.txt +++ /dev/null @@ -1,13 +0,0 @@ - -Tracing Joy Execution -===================== - - -``joy.utils.pretty_print`` --------------------------- - - -.. automodule:: joy.utils.pretty_print - :members: - - diff --git a/docs/sphinx_docs/_build/html/_sources/stack.rst.txt b/docs/sphinx_docs/_build/html/_sources/stack.rst.txt deleted file mode 100644 index a4af099..0000000 --- a/docs/sphinx_docs/_build/html/_sources/stack.rst.txt +++ /dev/null @@ -1,13 +0,0 @@ - -Stack or Quote or Sequence or List... -===================================== - - -``joy.utils.stack`` ----------------------- - - -.. automodule:: joy.utils.stack - :members: - - diff --git a/docs/sphinx_docs/_build/html/_sources/types.rst.txt b/docs/sphinx_docs/_build/html/_sources/types.rst.txt deleted file mode 100644 index 5491f3a..0000000 --- a/docs/sphinx_docs/_build/html/_sources/types.rst.txt +++ /dev/null @@ -1,153 +0,0 @@ - -Type Inference of Joy Expressions -================================= - -UPDATE: May 2020 - I removed the type inference code in `joy.utils.types` -but you can find it in the `v0.4.0` tag here: -https://osdn.net/projects/joypy/scm/hg/Joypy/tags - - -Two kinds of type inference are provided, a simple inferencer that can -handle functions that have a single stack effect (aka "type signature") -and that can generate Python code for a limited subset of those -functions, and a more complex inferencer/interpreter hybrid that can -infer the stack effects of most Joy expressions, including multiple stack -effects, unbounded sequences of values, and combinators (if enough -information is available.) - - -``joy.utils.types`` -------------------- - - -Curently (asterix after name indicates a function that can be -auto-compiled to Python):: - - _Tree_add_Ee = ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) * - _Tree_delete_R0 = ([a2 ...1] a1 -- [a2 ...1] a2 a1 a1) * - _Tree_delete_clear_stuff = (a3 a2 [a1 ...1] -- [...1]) * - _Tree_get_E = ([a3 a4 ...1] a2 a1 -- a4) * - add = (n1 n2 -- n3) - and = (b1 b2 -- b3) - bool = (a1 -- b1) - ccons = (a2 a1 [...1] -- [a2 a1 ...1]) * - cons = (a1 [...0] -- [a1 ...0]) * - div = (n1 n2 -- n3) - divmod = (n2 n1 -- n4 n3) - dup = (a1 -- a1 a1) * - dupd = (a2 a1 -- a2 a2 a1) * - dupdd = (a3 a2 a1 -- a3 a3 a2 a1) * - eq = (n1 n2 -- b1) - first = ([a1 ...1] -- a1) * - first_two = ([a1 a2 ...1] -- a1 a2) * - floordiv = (n1 n2 -- n3) - fourth = ([a1 a2 a3 a4 ...1] -- a4) * - ge = (n1 n2 -- b1) - gt = (n1 n2 -- b1) - le = (n1 n2 -- b1) - lshift = (n1 n2 -- n3) - lt = (n1 n2 -- b1) - modulus = (n1 n2 -- n3) - mul = (n1 n2 -- n3) - ne = (n1 n2 -- b1) - neg = (n1 -- n2) - not = (a1 -- b1) - over = (a2 a1 -- a2 a1 a2) * - pm = (n2 n1 -- n4 n3) - pop = (a1 --) * - popd = (a2 a1 -- a1) * - popdd = (a3 a2 a1 -- a2 a1) * - popop = (a2 a1 --) * - popopd = (a3 a2 a1 -- a1) * - popopdd = (a4 a3 a2 a1 -- a2 a1) * - pow = (n1 n2 -- n3) - pred = (n1 -- n2) - rest = ([a1 ...0] -- [...0]) * - rolldown = (a1 a2 a3 -- a2 a3 a1) * - rollup = (a1 a2 a3 -- a3 a1 a2) * - rrest = ([a1 a2 ...1] -- [...1]) * - rshift = (n1 n2 -- n3) - second = ([a1 a2 ...1] -- a2) * - sqrt = (n1 -- n2) - stack = (... -- ... [...]) * - stuncons = (... a1 -- ... a1 a1 [...]) * - stununcons = (... a2 a1 -- ... a2 a1 a1 a2 [...]) * - sub = (n1 n2 -- n3) - succ = (n1 -- n2) - swaack = ([...1] -- [...0]) * - swap = (a1 a2 -- a2 a1) * - swons = ([...1] a1 -- [a1 ...1]) * - third = ([a1 a2 a3 ...1] -- a3) * - truediv = (n1 n2 -- n3) - tuck = (a2 a1 -- a1 a2 a1) * - uncons = ([a1 ...0] -- a1 [...0]) * - unit = (a1 -- [a1 ]) * - unswons = ([a1 ...1] -- [...1] a1) * - - -Example output of the ``infer()`` function. The first number on each -line is the depth of the Python stack. It goes down when the function -backtracks. The next thing on each line is the currently-computed stack -effect so far. It starts with the empty "identity function" and proceeds -through the expression, which is the rest of each line. The function -acts like an interpreter but instead of executing the terms of the -expression it composes them, but for combinators it *does* execute them, -using the output side of the stack effect as the stack. This seems to -work fine. With proper definitions for the behavior of the combinators -that can have more than one effect (like ``branch`` or ``loop``) the -``infer()`` function seems to be able to handle anything I throw at it so -far. - -:: - - 7 (--) ∘ pop swap rolldown rest rest cons cons - 10 (a1 --) ∘ swap rolldown rest rest cons cons - 13 (a3 a2 a1 -- a2 a3) ∘ rolldown rest rest cons cons - 16 (a4 a3 a2 a1 -- a2 a3 a4) ∘ rest rest cons cons - 19 ([a4 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ rest cons cons - 22 ([a4 a5 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ cons cons - 25 ([a4 a5 ...1] a3 a2 a1 -- a2 [a3 ...1]) ∘ cons - 28 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘ - ---------------------------------------- - ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) - - -Here's another example (implementing ``ifte``) using some combinators:: - - 7 (--) ∘ [pred] [mul] [div] [nullary bool] dipd branch - 8 (-- [pred ...2]) ∘ [mul] [div] [nullary bool] dipd branch - 9 (-- [pred ...2] [mul ...3]) ∘ [div] [nullary bool] dipd branch - 10 (-- [pred ...2] [mul ...3] [div ...4]) ∘ [nullary bool] dipd branch - 11 (-- [pred ...2] [mul ...3] [div ...4] [nullary bool ...5]) ∘ dipd branch - 15 (-- [pred ...5]) ∘ nullary bool [mul] [div] branch - 19 (-- [pred ...2]) ∘ [stack] dinfrirst bool [mul] [div] branch - 20 (-- [pred ...2] [stack ]) ∘ dinfrirst bool [mul] [div] branch - 22 (-- [pred ...2] [stack ]) ∘ dip infra first bool [mul] [div] branch - 26 (--) ∘ stack [pred] infra first bool [mul] [div] branch - 29 (... -- ... [...]) ∘ [pred] infra first bool [mul] [div] branch - 30 (... -- ... [...] [pred ...1]) ∘ infra first bool [mul] [div] branch - 34 (--) ∘ pred s1 swaack first bool [mul] [div] branch - 37 (n1 -- n2) ∘ [n1] swaack first bool [mul] [div] branch - 38 (... n1 -- ... n2 [n1 ...]) ∘ swaack first bool [mul] [div] branch - 41 (... n1 -- ... n1 [n2 ...]) ∘ first bool [mul] [div] branch - 44 (n1 -- n1 n2) ∘ bool [mul] [div] branch - 47 (n1 -- n1 b1) ∘ [mul] [div] branch - 48 (n1 -- n1 b1 [mul ...1]) ∘ [div] branch - 49 (n1 -- n1 b1 [mul ...1] [div ...2]) ∘ branch - 53 (n1 -- n1) ∘ div - 56 (f2 f1 -- f3) ∘ - 56 (i1 f1 -- f2) ∘ - 56 (f1 i1 -- f2) ∘ - 56 (i2 i1 -- f1) ∘ - 53 (n1 -- n1) ∘ mul - 56 (f2 f1 -- f3) ∘ - 56 (i1 f1 -- f2) ∘ - 56 (f1 i1 -- f2) ∘ - 56 (i2 i1 -- i3) ∘ - ---------------------------------------- - (f2 f1 -- f3) - (i1 f1 -- f2) - (f1 i1 -- f2) - (i2 i1 -- f1) - (i2 i1 -- i3) - diff --git a/docs/sphinx_docs/_build/html/_static/alabaster.css b/docs/sphinx_docs/_build/html/_static/alabaster.css deleted file mode 100644 index 0eddaeb..0000000 --- a/docs/sphinx_docs/_build/html/_static/alabaster.css +++ /dev/null @@ -1,701 +0,0 @@ -@import url("basic.css"); - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: Georgia, serif; - font-size: 17px; - background-color: #fff; - color: #000; - margin: 0; - padding: 0; -} - - -div.document { - width: 940px; - margin: 30px auto 0 auto; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 220px; -} - -div.sphinxsidebar { - width: 220px; - font-size: 14px; - line-height: 1.5; -} - -hr { - border: 1px solid #B1B4B6; -} - -div.body { - background-color: #fff; - color: #3E4349; - padding: 0 30px 0 30px; -} - -div.body > .section { - text-align: left; -} - -div.footer { - width: 940px; - margin: 20px auto 30px auto; - font-size: 14px; - color: #888; - text-align: right; -} - -div.footer a { - color: #888; -} - -p.caption { - font-family: inherit; - font-size: inherit; -} - - -div.relations { - display: none; -} - - -div.sphinxsidebar a { - color: #444; - text-decoration: none; - border-bottom: 1px dotted #999; -} - -div.sphinxsidebar a:hover { - border-bottom: 1px solid #999; -} - -div.sphinxsidebarwrapper { - padding: 18px 10px; -} - -div.sphinxsidebarwrapper p.logo { - padding: 0; - margin: -10px 0 0 0px; - text-align: center; -} - -div.sphinxsidebarwrapper h1.logo { - margin-top: -10px; - text-align: center; - margin-bottom: 5px; - text-align: left; -} - -div.sphinxsidebarwrapper h1.logo-name { - margin-top: 0px; -} - -div.sphinxsidebarwrapper p.blurb { - margin-top: 0; - font-style: normal; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: Georgia, serif; - color: #444; - font-size: 24px; - font-weight: normal; - margin: 0 0 5px 0; - padding: 0; -} - -div.sphinxsidebar h4 { - font-size: 20px; -} - -div.sphinxsidebar h3 a { - color: #444; -} - -div.sphinxsidebar p.logo a, -div.sphinxsidebar h3 a, -div.sphinxsidebar p.logo a:hover, -div.sphinxsidebar h3 a:hover { - border: none; -} - -div.sphinxsidebar p { - color: #555; - margin: 10px 0; -} - -div.sphinxsidebar ul { - margin: 10px 0; - padding: 0; - color: #000; -} - -div.sphinxsidebar ul li.toctree-l1 > a { - font-size: 120%; -} - -div.sphinxsidebar ul li.toctree-l2 > a { - font-size: 110%; -} - -div.sphinxsidebar input { - border: 1px solid #CCC; - font-family: Georgia, serif; - font-size: 1em; -} - -div.sphinxsidebar hr { - border: none; - height: 1px; - color: #AAA; - background: #AAA; - - text-align: left; - margin-left: 0; - width: 50%; -} - -div.sphinxsidebar .badge { - border-bottom: none; -} - -div.sphinxsidebar .badge:hover { - border-bottom: none; -} - -/* To address an issue with donation coming after search */ -div.sphinxsidebar h3.donation { - margin-top: 10px; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #004B6B; - text-decoration: underline; -} - -a:hover { - color: #6D4100; - text-decoration: underline; -} - -div.body h1, -div.body h2, -div.body h3, -div.body h4, -div.body h5, -div.body h6 { - font-family: Georgia, serif; - font-weight: normal; - margin: 30px 0px 10px 0px; - padding: 0; -} - -div.body h1 { margin-top: 0; padding-top: 0; font-size: 240%; } -div.body h2 { font-size: 180%; } -div.body h3 { font-size: 150%; } -div.body h4 { font-size: 130%; } -div.body h5 { font-size: 100%; } -div.body h6 { font-size: 100%; } - -a.headerlink { - color: #DDD; - padding: 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - color: #444; - background: #EAEAEA; -} - -div.body p, div.body dd, div.body li { - line-height: 1.4em; -} - -div.admonition { - margin: 20px 0px; - padding: 10px 30px; - background-color: #EEE; - border: 1px solid #CCC; -} - -div.admonition tt.xref, div.admonition code.xref, div.admonition a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fafafa; -} - -div.admonition p.admonition-title { - font-family: Georgia, serif; - font-weight: normal; - font-size: 24px; - margin: 0 0 10px 0; - padding: 0; - line-height: 1; -} - -div.admonition p.last { - margin-bottom: 0; -} - -div.highlight { - background-color: #fff; -} - -dt:target, .highlight { - background: #FAF3E8; -} - -div.warning { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.danger { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.error { - background-color: #FCC; - border: 1px solid #FAA; - -moz-box-shadow: 2px 2px 4px #D52C2C; - -webkit-box-shadow: 2px 2px 4px #D52C2C; - box-shadow: 2px 2px 4px #D52C2C; -} - -div.caution { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.attention { - background-color: #FCC; - border: 1px solid #FAA; -} - -div.important { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.note { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.tip { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.hint { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.seealso { - background-color: #EEE; - border: 1px solid #CCC; -} - -div.topic { - background-color: #EEE; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre, tt, code { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.9em; -} - -.hll { - background-color: #FFC; - margin: 0 -12px; - padding: 0 12px; - display: block; -} - -img.screenshot { -} - -tt.descname, tt.descclassname, code.descname, code.descclassname { - font-size: 0.95em; -} - -tt.descname, code.descname { - padding-right: 0.08em; -} - -img.screenshot { - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils { - border: 1px solid #888; - -moz-box-shadow: 2px 2px 4px #EEE; - -webkit-box-shadow: 2px 2px 4px #EEE; - box-shadow: 2px 2px 4px #EEE; -} - -table.docutils td, table.docutils th { - border: 1px solid #888; - padding: 0.25em 0.7em; -} - -table.field-list, table.footnote { - border: none; - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - -table.footnote { - margin: 15px 0; - width: 100%; - border: 1px solid #EEE; - background: #FDFDFD; - font-size: 0.9em; -} - -table.footnote + table.footnote { - margin-top: -15px; - border-top: none; -} - -table.field-list th { - padding: 0 0.8em 0 0; -} - -table.field-list td { - padding: 0; -} - -table.field-list p { - margin-bottom: 0.8em; -} - -/* Cloned from - * https://github.com/sphinx-doc/sphinx/commit/ef60dbfce09286b20b7385333d63a60321784e68 - */ -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -table.footnote td.label { - width: .1px; - padding: 0.3em 0 0.3em 0.5em; -} - -table.footnote td { - padding: 0.3em 0.5em; -} - -dl { - margin: 0; - padding: 0; -} - -dl dd { - margin-left: 30px; -} - -blockquote { - margin: 0 0 0 30px; - padding: 0; -} - -ul, ol { - /* Matches the 30px from the narrow-screen "li > ul" selector below */ - margin: 10px 0 10px 30px; - padding: 0; -} - -pre { - background: #EEE; - padding: 7px 30px; - margin: 15px 0px; - line-height: 1.3em; -} - -div.viewcode-block:target { - background: #ffd; -} - -dl pre, blockquote pre, li pre { - margin-left: 0; - padding-left: 30px; -} - -tt, code { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ -} - -tt.xref, code.xref, a tt { - background-color: #FBFBFB; - border-bottom: 1px solid #fff; -} - -a.reference { - text-decoration: none; - border-bottom: 1px dotted #004B6B; -} - -/* Don't put an underline on images */ -a.image-reference, a.image-reference:hover { - border-bottom: none; -} - -a.reference:hover { - border-bottom: 1px solid #6D4100; -} - -a.footnote-reference { - text-decoration: none; - font-size: 0.7em; - vertical-align: top; - border-bottom: 1px dotted #004B6B; -} - -a.footnote-reference:hover { - border-bottom: 1px solid #6D4100; -} - -a:hover tt, a:hover code { - background: #EEE; -} - - -@media screen and (max-width: 870px) { - - div.sphinxsidebar { - display: none; - } - - div.document { - width: 100%; - - } - - div.documentwrapper { - margin-left: 0; - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - } - - div.bodywrapper { - margin-top: 0; - margin-right: 0; - margin-bottom: 0; - margin-left: 0; - } - - ul { - margin-left: 0; - } - - li > ul { - /* Matches the 30px from the "ul, ol" selector above */ - margin-left: 30px; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .bodywrapper { - margin: 0; - } - - .footer { - width: auto; - } - - .github { - display: none; - } - - - -} - - - -@media screen and (max-width: 875px) { - - body { - margin: 0; - padding: 20px 30px; - } - - div.documentwrapper { - float: none; - background: #fff; - } - - div.sphinxsidebar { - display: block; - float: none; - width: 102.5%; - margin: 50px -30px -20px -30px; - padding: 10px 20px; - background: #333; - color: #FFF; - } - - div.sphinxsidebar h3, div.sphinxsidebar h4, div.sphinxsidebar p, - div.sphinxsidebar h3 a { - color: #fff; - } - - div.sphinxsidebar a { - color: #AAA; - } - - div.sphinxsidebar p.logo { - display: none; - } - - div.document { - width: 100%; - margin: 0; - } - - div.footer { - display: none; - } - - div.bodywrapper { - margin: 0; - } - - div.body { - min-height: 0; - padding: 0; - } - - .rtd_doc_footer { - display: none; - } - - .document { - width: auto; - } - - .footer { - width: auto; - } - - .footer { - width: auto; - } - - .github { - display: none; - } -} - - -/* misc. */ - -.revsys-inline { - display: none!important; -} - -/* Make nested-list/multi-paragraph items look better in Releases changelog - * pages. Without this, docutils' magical list fuckery causes inconsistent - * formatting between different release sub-lists. - */ -div#changelog > div.section > ul > li > p:only-child { - margin-bottom: 0; -} - -/* Hide fugly table cell borders in ..bibliography:: directive output */ -table.docutils.citation, table.docutils.citation td, table.docutils.citation th { - border: none; - /* Below needed in some edge cases; if not applied, bottom shadows appear */ - -moz-box-shadow: none; - -webkit-box-shadow: none; - box-shadow: none; -} - - -/* relbar */ - -.related { - line-height: 30px; - width: 100%; - font-size: 0.9rem; -} - -.related.top { - border-bottom: 1px solid #EEE; - margin-bottom: 20px; -} - -.related.bottom { - border-top: 1px solid #EEE; -} - -.related ul { - padding: 0; - margin: 0; - list-style: none; -} - -.related li { - display: inline; -} - -nav#rellinks { - float: right; -} - -nav#rellinks li+li:before { - content: "|"; -} - -nav#breadcrumbs li+li:before { - content: "\00BB"; -} - -/* Hide certain items when printing */ -@media print { - div.related { - display: none; - } -} \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_static/basic.css b/docs/sphinx_docs/_build/html/_static/basic.css deleted file mode 100644 index ac9a52a..0000000 --- a/docs/sphinx_docs/_build/html/_static/basic.css +++ /dev/null @@ -1,909 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar li { - padding-bottom: 0.5em; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li p.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 450px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, figure.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, figure.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, figure.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, figure.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar, -aside.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -aside.sidebar > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -aside.sidebar::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure, figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption, figcaption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number, -figcaption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text, -figcaption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - -/* -- object description styles --------------------------------------------- */ - -.sig { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; -} - -.sig-name, code.descname { - background-color: transparent; - font-weight: bold; -} - -.sig-name { - font-size: 1.1em; -} - -code.descname { - font-size: 1.2em; -} - -.sig-prename, code.descclassname { - background-color: transparent; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.sig-param.n { - font-style: italic; -} - -/* C++ specific styling */ - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset; -} - -.sig.c .k, .sig.c .kt, -.sig.cpp .k, .sig.cpp .kt { - color: #0033B3; -} - -.sig.c .m, -.sig.cpp .m { - color: #1750EB; -} - -.sig.c .s, .sig.c .sc, -.sig.cpp .s, .sig.cpp .sc { - color: #067D17; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -dl.footnote > dt, -dl.citation > dt { - float: left; - margin-right: 0.5em; -} - -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; -} - -dl.footnote > dd:after, -dl.citation > dd:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dt:after { - content: ":"; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0 0.5em; - content: ":"; - display: inline-block; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; - -webkit-user-select: text; /* Safari fallback only */ - -webkit-user-select: none; /* Chrome/Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+ */ -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_static/custom.css b/docs/sphinx_docs/_build/html/_static/custom.css deleted file mode 100644 index 2a924f1..0000000 --- a/docs/sphinx_docs/_build/html/_static/custom.css +++ /dev/null @@ -1 +0,0 @@ -/* This file intentionally left blank. */ diff --git a/docs/sphinx_docs/_build/html/_static/doctools.js b/docs/sphinx_docs/_build/html/_static/doctools.js deleted file mode 100644 index e509e48..0000000 --- a/docs/sphinx_docs/_build/html/_static/doctools.js +++ /dev/null @@ -1,326 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - * - * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL - */ -jQuery.urldecode = function(x) { - if (!x) { - return x - } - return decodeURIComponent(x.replace(/\+/g, ' ')); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && - !jQuery(node.parentNode).hasClass(className) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - var bbox = node.parentElement.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { - this.initOnKeyListeners(); - } - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated === 'undefined') - return string; - return (typeof translated === 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated === 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - var url = new URL(window.location); - url.searchParams.delete('highlight'); - window.history.replaceState({}, '', url); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - }, - - initOnKeyListeners: function() { - $(document).keydown(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box, textarea, dropdown or button - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' - && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey - && !event.shiftKey) { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - break; - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - break; - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/docs/sphinx_docs/_build/html/_static/documentation_options.js b/docs/sphinx_docs/_build/html/_static/documentation_options.js deleted file mode 100644 index e9b7668..0000000 --- a/docs/sphinx_docs/_build/html/_static/documentation_options.js +++ /dev/null @@ -1,12 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '0.4.1', - LANGUAGE: 'None', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false -}; \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/_static/file.png b/docs/sphinx_docs/_build/html/_static/file.png deleted file mode 100644 index a858a410e4faa62ce324d814e4b816fff83a6fb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( diff --git a/docs/sphinx_docs/_build/html/_static/jquery-3.5.1.js b/docs/sphinx_docs/_build/html/_static/jquery-3.5.1.js deleted file mode 100644 index 5093733..0000000 --- a/docs/sphinx_docs/_build/html/_static/jquery-3.5.1.js +++ /dev/null @@ -1,10872 +0,0 @@ -/*! - * jQuery JavaScript Library v3.5.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2020-05-04T22:49Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var flat = arr.flat ? function( array ) { - return arr.flat.call( array ); -} : function( array ) { - return arr.concat.apply( [], array ); -}; - - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - -var isFunction = function isFunction( obj ) { - - // Support: Chrome <=57, Firefox <=52 - // In some browsers, typeof returns "function" for HTML elements - // (i.e., `typeof document.createElement( "object" ) === "function"`). - // We don't want to classify *any* DOM node as a function. - return typeof obj === "function" && typeof obj.nodeType !== "number"; - }; - - -var isWindow = function isWindow( obj ) { - return obj != null && obj === obj.window; - }; - - -var document = window.document; - - - - var preservedScriptAttributes = { - type: true, - src: true, - nonce: true, - noModule: true - }; - - function DOMEval( code, node, doc ) { - doc = doc || document; - - var i, val, - script = doc.createElement( "script" ); - - script.text = code; - if ( node ) { - for ( i in preservedScriptAttributes ) { - - // Support: Firefox 64+, Edge 18+ - // Some browsers don't support the "nonce" property on scripts. - // On the other hand, just using `getAttribute` is not enough as - // the `nonce` attribute is reset to an empty string whenever it - // becomes browsing-context connected. - // See https://github.com/whatwg/html/issues/2369 - // See https://html.spec.whatwg.org/#nonce-attributes - // The `node.getAttribute` check was added for the sake of - // `jQuery.globalEval` so that it can fake a nonce-containing node - // via an object. - val = node[ i ] || node.getAttribute && node.getAttribute( i ); - if ( val ) { - script.setAttribute( i, val ); - } - } - } - doc.head.appendChild( script ).parentNode.removeChild( script ); - } - - -function toType( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; -} -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.5.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - even: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return ( i + 1 ) % 2; - } ) ); - }, - - odd: function() { - return this.pushStack( jQuery.grep( this, function( _elem, i ) { - return i % 2; - } ) ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - copy = options[ name ]; - - // Prevent Object.prototype pollution - // Prevent never-ending loop - if ( name === "__proto__" || target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - src = target[ name ]; - - // Ensure proper type for the source value - if ( copyIsArray && !Array.isArray( src ) ) { - clone = []; - } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { - clone = {}; - } else { - clone = src; - } - copyIsArray = false; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - // Evaluates a script in a provided context; falls back to the global one - // if not specified. - globalEval: function( code, options, doc ) { - DOMEval( code, { nonce: options && options.nonce }, doc ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return flat( ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( _i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = toType( obj ); - - if ( isFunction( obj ) || isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.5 - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://js.foundation/ - * - * Date: 2020-03-14 - */ -( function( window ) { -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - nonnativeSelectorCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ( {} ).hasOwnProperty, - arr = [], - pop = arr.pop, - pushNative = arr.push, - push = arr.push, - slice = arr.slice, - - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[ i ] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + - "ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram - identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + - "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - - // "Attribute values must be CSS identifiers [capture 5] - // or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + - whitespace + "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + - whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + - "*" ), - rdescend = new RegExp( whitespace + "|>" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + - whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + - whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + - "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + - "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rhtml = /HTML$/i, - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), - funescape = function( escape, nonHex ) { - var high = "0x" + escape.slice( 1 ) - 0x10000; - - return nonHex ? - - // Strip the backslash prefix from a non-hex escape sequence - nonHex : - - // Replace a hexadecimal escape sequence with the encoded Unicode code point - // Support: IE <=11+ - // For values outside the Basic Multilingual Plane (BMP), manually construct a - // surrogate pair - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + - ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - inDisabledFieldset = addCombinator( - function( elem ) { - return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - ( arr = slice.call( preferredDoc.childNodes ) ), - preferredDoc.childNodes - ); - - // Support: Android<4.0 - // Detect silently failing push.apply - // eslint-disable-next-line no-unused-expressions - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - pushNative.apply( target, slice.call( els ) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - - // Can't trust NodeList.length - while ( ( target[ j++ ] = els[ i++ ] ) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - setDocument( context ); - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { - - // ID selector - if ( ( m = match[ 1 ] ) ) { - - // Document context - if ( nodeType === 9 ) { - if ( ( elem = context.getElementById( m ) ) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && ( elem = newContext.getElementById( m ) ) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[ 2 ] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !nonnativeSelectorCache[ selector + " " ] && - ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && - - // Support: IE 8 only - // Exclude object elements - ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { - - newSelector = selector; - newContext = context; - - // qSA considers elements outside a scoping root when evaluating child or - // descendant combinators, which is not what we want. - // In such cases, we work around the behavior by prefixing every selector in the - // list with an ID selector referencing the scope context. - // The technique has to be used as well when a leading combinator is used - // as such selectors are not recognized by querySelectorAll. - // Thanks to Andrew Dupont for this technique. - if ( nodeType === 1 && - ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - - // We can use :scope instead of the ID hack if the browser - // supports it & if we're not changing the context. - if ( newContext !== context || !support.scope ) { - - // Capture the context ID, setting it first if necessary - if ( ( nid = context.getAttribute( "id" ) ) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", ( nid = expando ) ); - } - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + - toSelector( groups[ i ] ); - } - newSelector = groups.join( "," ); - } - - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - nonnativeSelectorCache( selector, true ); - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return ( cache[ key + " " ] = value ); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement( "fieldset" ); - - try { - return !!fn( el ); - } catch ( e ) { - return false; - } finally { - - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split( "|" ), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[ i ] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( ( cur = cur.nextSibling ) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return ( name === "input" || name === "button" ) && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - inDisabledFieldset( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction( function( argument ) { - argument = +argument; - return markFunction( function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ ( j = matchIndexes[ i ] ) ] ) { - seed[ j ] = !( matches[ j ] = seed[ j ] ); - } - } - } ); - } ); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - var namespace = elem.namespaceURI, - docElem = ( elem.ownerDocument || elem ).documentElement; - - // Support: IE <=8 - // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes - // https://bugs.jquery.com/ticket/4833 - return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9 - 11+, Edge 12 - 18+ - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( preferredDoc != document && - ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, - // Safari 4 - 5 only, Opera <=11.6 - 12.x only - // IE/Edge & older browsers don't support the :scope pseudo-class. - // Support: Safari 6.0 only - // Safari 6.0 supports :scope but it's an alias of :root there. - support.scope = assert( function( el ) { - docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); - return typeof el.querySelectorAll !== "undefined" && - !el.querySelectorAll( ":scope fieldset div" ).length; - } ); - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert( function( el ) { - el.className = "i"; - return !el.getAttribute( "className" ); - } ); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert( function( el ) { - el.appendChild( document.createComment( "" ) ); - return !el.getElementsByTagName( "*" ).length; - } ); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert( function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - } ); - - // ID filter and find - if ( support.getById ) { - Expr.filter[ "ID" ] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute( "id" ) === attrId; - }; - }; - Expr.find[ "ID" ] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter[ "ID" ] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode( "id" ); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find[ "ID" ] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( ( elem = elems[ i++ ] ) ) { - node = elem.getAttributeNode( "id" ); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find[ "TAG" ] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { - - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert( function( el ) { - - var input; - - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll( "[selected]" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push( "~=" ); - } - - // Support: IE 11+, Edge 15 - 18+ - // IE 11/Edge don't find elements on a `[name='']` query in some cases. - // Adding a temporary attribute to the document before the selection works - // around the issue. - // Interestingly, IE 10 & older don't seem to have the issue. - input = document.createElement( "input" ); - input.setAttribute( "name", "" ); - el.appendChild( input ); - if ( !el.querySelectorAll( "[name='']" ).length ) { - rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + - whitespace + "*(?:''|\"\")" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll( ":checked" ).length ) { - rbuggyQSA.push( ":checked" ); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push( ".#.+[+~]" ); - } - - // Support: Firefox <=3.6 - 5 only - // Old Firefox doesn't throw on a badly-escaped identifier. - el.querySelectorAll( "\\\f" ); - rbuggyQSA.push( "[\\r\\n\\f]" ); - } ); - - assert( function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement( "input" ); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll( "[name=d]" ).length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: Opera 10 - 11 only - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll( "*,:x" ); - rbuggyQSA.push( ",.*:" ); - } ); - } - - if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector ) ) ) ) { - - assert( function( el ) { - - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - } ); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - ) ); - } : - function( a, b ) { - if ( b ) { - while ( ( b = b.parentNode ) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { - - // Choose the first element that is related to our preferred document - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( a == document || a.ownerDocument == preferredDoc && - contains( preferredDoc, a ) ) { - return -1; - } - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( b == document || b.ownerDocument == preferredDoc && - contains( preferredDoc, b ) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - return a == document ? -1 : - b == document ? 1 : - /* eslint-enable eqeqeq */ - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( ( cur = cur.parentNode ) ) { - ap.unshift( cur ); - } - cur = b; - while ( ( cur = cur.parentNode ) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[ i ] === bp[ i ] ) { - i++; - } - - return i ? - - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[ i ], bp[ i ] ) : - - // Otherwise nodes in our document sort first - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - /* eslint-disable eqeqeq */ - ap[ i ] == preferredDoc ? -1 : - bp[ i ] == preferredDoc ? 1 : - /* eslint-enable eqeqeq */ - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - setDocument( elem ); - - if ( support.matchesSelector && documentIsHTML && - !nonnativeSelectorCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch ( e ) { - nonnativeSelectorCache( expr, true ); - } - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( context.ownerDocument || context ) != document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - - // Set document vars if needed - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( ( elem.ownerDocument || elem ) != document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - ( val = elem.getAttributeNode( name ) ) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return ( sel + "" ).replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( ( elem = results[ i++ ] ) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - - // If no nodeType, this is expected to be an array - while ( ( node = elem[ i++ ] ) ) { - - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[ 1 ] = match[ 1 ].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[ 3 ] = ( match[ 3 ] || match[ 4 ] || - match[ 5 ] || "" ).replace( runescape, funescape ); - - if ( match[ 2 ] === "~=" ) { - match[ 3 ] = " " + match[ 3 ] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[ 1 ] = match[ 1 ].toLowerCase(); - - if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { - - // nth-* requires argument - if ( !match[ 3 ] ) { - Sizzle.error( match[ 0 ] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[ 4 ] = +( match[ 4 ] ? - match[ 5 ] + ( match[ 6 ] || 1 ) : - 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); - match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); - - // other types prohibit arguments - } else if ( match[ 3 ] ) { - Sizzle.error( match[ 0 ] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[ 6 ] && match[ 2 ]; - - if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[ 3 ] ) { - match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - - // Get excess from tokenize (recursively) - ( excess = tokenize( unquoted, true ) ) && - - // advance to the next closing parenthesis - ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { - - // excess is a negative index - match[ 0 ] = match[ 0 ].slice( 0, excess ); - match[ 2 ] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { - return true; - } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - ( pattern = new RegExp( "(^|" + whitespace + - ")" + className + "(" + whitespace + "|$)" ) ) && classCache( - className, function( elem ) { - return pattern.test( - typeof elem.className === "string" && elem.className || - typeof elem.getAttribute !== "undefined" && - elem.getAttribute( "class" ) || - "" - ); - } ); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - /* eslint-disable max-len */ - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - /* eslint-enable max-len */ - - }; - }, - - "CHILD": function( type, what, _argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, _context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( ( node = node[ dir ] ) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( ( node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - - // Use previously-cached element index if available - if ( useCache ) { - - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - - // Use the same loop as above to seek `elem` from the start - while ( ( node = ++nodeIndex && node && node[ dir ] || - ( diff = nodeIndex = 0 ) || start.pop() ) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || - ( node[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - ( outerCache[ node.uniqueID ] = {} ); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction( function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[ i ] ); - seed[ idx ] = !( matches[ idx ] = matched[ i ] ); - } - } ) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - - // Potentially complex pseudos - "not": markFunction( function( selector ) { - - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction( function( seed, matches, _context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( ( elem = unmatched[ i ] ) ) { - seed[ i ] = !( matches[ i ] = elem ); - } - } - } ) : - function( elem, _context, xml ) { - input[ 0 ] = elem; - matcher( input, null, xml, results ); - - // Don't keep the element (issue #299) - input[ 0 ] = null; - return !results.pop(); - }; - } ), - - "has": markFunction( function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - } ), - - "contains": markFunction( function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; - }; - } ), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - - // lang value must be a valid identifier - if ( !ridentifier.test( lang || "" ) ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( ( elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); - return false; - }; - } ), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && - ( !document.hasFocus || document.hasFocus() ) && - !!( elem.type || elem.href || ~elem.tabIndex ); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return ( nodeName === "input" && !!elem.checked ) || - ( nodeName === "option" && !!elem.selected ); - }, - - "selected": function( elem ) { - - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - // eslint-disable-next-line no-unused-expressions - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos[ "empty" ]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( ( attr = elem.getAttribute( "type" ) ) == null || - attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo( function() { - return [ 0 ]; - } ), - - "last": createPositionalPseudo( function( _matchIndexes, length ) { - return [ length - 1 ]; - } ), - - "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - } ), - - "even": createPositionalPseudo( function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "odd": createPositionalPseudo( function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? - argument + length : - argument > length ? - length : - argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ), - - "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - } ) - } -}; - -Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || ( match = rcomma.exec( soFar ) ) ) { - if ( match ) { - - // Don't consume trailing commas as valid - soFar = soFar.slice( match[ 0 ].length ) || soFar; - } - groups.push( ( tokens = [] ) ); - } - - matched = false; - - // Combinators - if ( ( match = rcombinators.exec( soFar ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - - // Cast descendant combinators to space - type: match[ 0 ].replace( rtrim, " " ) - } ); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || - ( match = preFilters[ type ]( match ) ) ) ) { - matched = match.shift(); - tokens.push( { - value: matched, - type: type, - matches: match - } ); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[ i ].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( ( elem = elem[ dir ] ) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || ( elem[ expando ] = {} ); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || - ( outerCache[ elem.uniqueID ] = {} ); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( ( oldCache = uniqueCache[ key ] ) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return ( newCache[ 2 ] = oldCache[ 2 ] ); - } else { - - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[ i ]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[ 0 ]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[ i ], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( ( elem = unmatched[ i ] ) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction( function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( - selector || "*", - context.nodeType ? [ context ] : context, - [] - ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( ( elem = temp[ i ] ) ) { - matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) ) { - - // Restore matcherIn since elem is not yet a final match - temp.push( ( matcherIn[ i ] = elem ) ); - } - } - postFinder( null, ( matcherOut = [] ), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( ( elem = matcherOut[ i ] ) && - ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { - - seed[ temp ] = !( results[ temp ] = elem ); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - } ); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[ 0 ].type ], - implicitRelative = leadingRelative || Expr.relative[ " " ], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - ( checkContext = context ).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { - matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; - } else { - matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[ j ].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens - .slice( 0, i - 1 ) - .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), - - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), - len = elems.length; - - if ( outermost ) { - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - outermostContext = context == document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - - // Support: IE 11+, Edge 17 - 18+ - // IE/Edge sometimes throw a "Permission denied" error when strict-comparing - // two documents; shallow comparisons work. - // eslint-disable-next-line eqeqeq - if ( !context && elem.ownerDocument != document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( ( matcher = elementMatchers[ j++ ] ) ) { - if ( matcher( elem, context || document, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - - // They will have gone through all possible matchers - if ( ( elem = !matcher && elem ) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( ( matcher = setMatchers[ j++ ] ) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !( unmatched[ i ] || setMatched[ i ] ) ) { - setMatched[ i ] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[ i ] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( - selector, - matcherFromGroupMatchers( elementMatchers, setMatchers ) - ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( ( selector = compiled.selector || selector ) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[ 0 ] = match[ 0 ].slice( 0 ); - if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { - - context = ( Expr.find[ "ID" ]( token.matches[ 0 ] - .replace( runescape, funescape ), context ) || [] )[ 0 ]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[ i ]; - - // Abort if we hit a combinator - if ( Expr.relative[ ( type = token.type ) ] ) { - break; - } - if ( ( find = Expr.find[ type ] ) ) { - - // Search, expanding context for leading sibling combinators - if ( ( seed = find( - token.matches[ 0 ].replace( runescape, funescape ), - rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || - context - ) ) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert( function( el ) { - - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; -} ); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert( function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute( "href" ) === "#"; -} ) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - } ); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert( function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -} ) ) { - addHandle( "value", function( elem, _name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - } ); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert( function( el ) { - return el.getAttribute( "disabled" ) == null; -} ) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - ( val = elem.getAttributeNode( name ) ) && val.specified ? - val.value : - null; - } - } ); -} - -return Sizzle; - -} )( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Filtered directly for both simple and complex selectors - return jQuery.filter( qualifier, elements, not ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, _i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, _i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, _i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( elem.contentDocument != null && - - // Support: IE 11+ - // elements with no `data` attribute has an object - // `contentDocument` with a `null` prototype. - getProto( elem.contentDocument ) ) { - - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && toType( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( _i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // rejected_handlers.disable - // fulfilled_handlers.disable - tuples[ 3 - i ][ 3 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock, - - // progress_handlers.lock - tuples[ 0 ][ 3 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( toType( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, _key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; - - -// Matches dashed string for camelizing -var rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g; - -// Used by camelCase as callback to replace() -function fcamelCase( _all, letter ) { - return letter.toUpperCase(); -} - -// Convert dashed to camelCase; used by the css and data modules -// Support: IE <=9 - 11, Edge 12 - 15 -// Microsoft forgot to hump their vendor prefix (#9572) -function camelCase( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); -} -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( camelCase ); - } else { - key = camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var documentElement = document.documentElement; - - - - var isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ); - }, - composed = { composed: true }; - - // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only - // Check attachment across shadow DOM boundaries when possible (gh-3504) - // Support: iOS 10.0-10.2 only - // Early iOS 10 versions support `attachShadow` but not `getRootNode`, - // leading to errors. We need to check for `getRootNode`. - if ( documentElement.getRootNode ) { - isAttached = function( elem ) { - return jQuery.contains( elem.ownerDocument, elem ) || - elem.getRootNode( composed ) === elem.ownerDocument; - }; - } -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - isAttached( elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, scale, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = elem.nodeType && - ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Support: Firefox <=54 - // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) - initial = initial / 2; - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - while ( maxIterations-- ) { - - // Evaluate and update our best guess (doubling guesses that zero out). - // Finish if the scale equals or crosses 1 (making the old*new product non-positive). - jQuery.style( elem, prop, initialInUnit + unit ); - if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { - maxIterations = 0; - } - initialInUnit = initialInUnit / scale; - - } - - initialInUnit = initialInUnit * 2; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); - -var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); - - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; - - // Support: IE <=9 only - // IE <=9 replaces "; - support.option = !!div.lastChild; -} )(); - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// Support: IE <=9 only -if ( !support.option ) { - wrapMap.optgroup = wrapMap.option = [ 1, "" ]; -} - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, attached, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( toType( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - attached = isAttached( elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( attached ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 - 11+ -// focus() and blur() are asynchronous, except when they are no-op. -// So expect focus to be synchronous when the element is already active, -// and blur to be synchronous when the element is not already active. -// (focus and blur are always synchronous in other supported browsers, -// this just defines when we can count on it). -function expectSync( elem, type ) { - return ( elem === safeActiveElement() ) === ( type === "focus" ); -} - -// Support: IE <=9 only -// Accessing document.activeElement can throw unexpectedly -// https://bugs.jquery.com/ticket/13393 -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Only attach events to objects that accept data - if ( !acceptData( elem ) ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = Object.create( null ); - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( nativeEvent ), - - handlers = ( - dataPriv.get( this, "events" ) || Object.create( null ) - )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // If the event is namespaced, then each handler is only invoked if it is - // specially universal or its namespaces are a superset of the event's. - if ( !event.rnamespace || handleObj.namespace === false || - event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - - // Utilize native event to ensure correct state for checkable inputs - setup: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Claim the first handler - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - // dataPriv.set( el, "click", ... ) - leverageNative( el, "click", returnTrue ); - } - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function( data ) { - - // For mutual compressibility with _default, replace `this` access with a local var. - // `|| data` is dead code meant only to preserve the variable through minification. - var el = this || data; - - // Force setup before triggering a click - if ( rcheckableType.test( el.type ) && - el.click && nodeName( el, "input" ) ) { - - leverageNative( el, "click" ); - } - - // Return non-false to allow normal event-path propagation - return true; - }, - - // For cross-browser consistency, suppress native .click() on links - // Also prevent it if we're currently inside a leveraged native-event stack - _default: function( event ) { - var target = event.target; - return rcheckableType.test( target.type ) && - target.click && nodeName( target, "input" ) && - dataPriv.get( target, "click" ) || - nodeName( target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -// Ensure the presence of an event listener that handles manually-triggered -// synthetic events by interrupting progress until reinvoked in response to -// *native* events that it fires directly, ensuring that state changes have -// already occurred before other listeners are invoked. -function leverageNative( el, type, expectSync ) { - - // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add - if ( !expectSync ) { - if ( dataPriv.get( el, type ) === undefined ) { - jQuery.event.add( el, type, returnTrue ); - } - return; - } - - // Register the controller as a special universal handler for all event namespaces - dataPriv.set( el, type, false ); - jQuery.event.add( el, type, { - namespace: false, - handler: function( event ) { - var notAsync, result, - saved = dataPriv.get( this, type ); - - if ( ( event.isTrigger & 1 ) && this[ type ] ) { - - // Interrupt processing of the outer synthetic .trigger()ed event - // Saved data should be false in such cases, but might be a leftover capture object - // from an async native handler (gh-4350) - if ( !saved.length ) { - - // Store arguments for use when handling the inner native event - // There will always be at least one argument (an event object), so this array - // will not be confused with a leftover capture object. - saved = slice.call( arguments ); - dataPriv.set( this, type, saved ); - - // Trigger the native event and capture its result - // Support: IE <=9 - 11+ - // focus() and blur() are asynchronous - notAsync = expectSync( this, type ); - this[ type ](); - result = dataPriv.get( this, type ); - if ( saved !== result || notAsync ) { - dataPriv.set( this, type, false ); - } else { - result = {}; - } - if ( saved !== result ) { - - // Cancel the outer synthetic event - event.stopImmediatePropagation(); - event.preventDefault(); - return result.value; - } - - // If this is an inner synthetic event for an event with a bubbling surrogate - // (focus or blur), assume that the surrogate already propagated from triggering the - // native event and prevent that from happening again here. - // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the - // bubbling surrogate propagates *after* the non-bubbling base), but that seems - // less bad than duplication. - } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { - event.stopPropagation(); - } - - // If this is a native event triggered above, everything is now in order - // Fire an inner synthetic event with the original arguments - } else if ( saved.length ) { - - // ...and capture the result - dataPriv.set( this, type, { - value: jQuery.event.trigger( - - // Support: IE <=9 - 11+ - // Extend with the prototype to reset the above stopImmediatePropagation() - jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), - saved.slice( 1 ), - this - ) - } ); - - // Abort handling of the native event - event.stopImmediatePropagation(); - } - } - } ); -} - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || Date.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - code: true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { - jQuery.event.special[ type ] = { - - // Utilize native event if possible so blur/focus sequence is correct - setup: function() { - - // Claim the first handler - // dataPriv.set( this, "focus", ... ) - // dataPriv.set( this, "blur", ... ) - leverageNative( this, type, expectSync ); - - // Return false to allow normal processing in the caller - return false; - }, - trigger: function() { - - // Force setup before trigger - leverageNative( this, type ); - - // Return non-false to allow normal event-path propagation - return true; - }, - - delegateType: delegateType - }; -} ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - // Support: IE <=10 - 11, Edge 12 - 13 only - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( elem ).children( "tbody" )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { - elem.type = elem.type.slice( 5 ); - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.get( src ); - events = pdataOld.events; - - if ( events ) { - dataPriv.remove( dest, "handle events" ); - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = flat( args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - valueIsFunction = isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( valueIsFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( valueIsFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl && !node.noModule ) { - jQuery._evalUrl( node.src, { - nonce: node.nonce || node.getAttribute( "nonce" ) - }, doc ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && isAttached( node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html; - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = isAttached( elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - -var swap = function( elem, options, callback ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.call( elem ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - -var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - container.style.cssText = "position:absolute;left:-11111px;width:60px;" + - "margin-top:1px;padding:0;border:0"; - div.style.cssText = - "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + - "margin:auto;border:1px;padding:1px;" + - "width:60%;top:1%"; - documentElement.appendChild( container ).appendChild( div ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; - - // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 - // Some styles come back with percentage values, even though they shouldn't - div.style.right = "60%"; - pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; - - // Support: IE 9 - 11 only - // Detect misreporting of content dimensions for box-sizing:border-box elements - boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; - - // Support: IE 9 only - // Detect overflow:scroll screwiness (gh-3699) - // Support: Chrome <=64 - // Don't get tricked when zoom affects offsetWidth (gh-4029) - div.style.position = "absolute"; - scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - function roundPixelMeasures( measure ) { - return Math.round( parseFloat( measure ) ); - } - - var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, - reliableTrDimensionsVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - jQuery.extend( support, { - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelBoxStyles: function() { - computeStyleTests(); - return pixelBoxStylesVal; - }, - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - }, - scrollboxSize: function() { - computeStyleTests(); - return scrollboxSizeVal; - }, - - // Support: IE 9 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Behavior in IE 9 is more subtle than in newer versions & it passes - // some versions of this test; make sure not to make it pass there! - reliableTrDimensions: function() { - var table, tr, trChild, trStyle; - if ( reliableTrDimensionsVal == null ) { - table = document.createElement( "table" ); - tr = document.createElement( "tr" ); - trChild = document.createElement( "div" ); - - table.style.cssText = "position:absolute;left:-11111px"; - tr.style.height = "1px"; - trChild.style.height = "9px"; - - documentElement - .appendChild( table ) - .appendChild( tr ) - .appendChild( trChild ); - - trStyle = window.getComputedStyle( tr ); - reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; - - documentElement.removeChild( table ); - } - return reliableTrDimensionsVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !isAttached( elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style, - vendorProps = {}; - -// Return a vendor-prefixed property or undefined -function vendorPropName( name ) { - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a potentially-mapped jQuery.cssProps or vendor prefixed property -function finalPropName( name ) { - var final = jQuery.cssProps[ name ] || vendorProps[ name ]; - - if ( final ) { - return final; - } - if ( name in emptyStyle ) { - return name; - } - return vendorProps[ name ] = vendorPropName( name ) || name; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }; - -function setPositiveNumber( _elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { - var i = dimension === "width" ? 1 : 0, - extra = 0, - delta = 0; - - // Adjustment may not be necessary - if ( box === ( isBorderBox ? "border" : "content" ) ) { - return 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin - if ( box === "margin" ) { - delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); - } - - // If we get here with a content-box, we're seeking "padding" or "border" or "margin" - if ( !isBorderBox ) { - - // Add padding - delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // For "border" or "margin", add border - if ( box !== "padding" ) { - delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - - // But still keep track of it otherwise - } else { - extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - - // If we get here with a border-box (content + padding + border), we're seeking "content" or - // "padding" or "margin" - } else { - - // For "content", subtract padding - if ( box === "content" ) { - delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // For "content" or "padding", subtract border - if ( box !== "margin" ) { - delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - // Account for positive content-box scroll gutter when requested by providing computedVal - if ( !isBorderBox && computedVal >= 0 ) { - - // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border - // Assuming integer scroll gutter, subtract the rest and round down - delta += Math.max( 0, Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - computedVal - - delta - - extra - - 0.5 - - // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter - // Use an explicit zero to avoid NaN (gh-3964) - ) ) || 0; - } - - return delta; -} - -function getWidthOrHeight( elem, dimension, extra ) { - - // Start with computed style - var styles = getStyles( elem ), - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). - // Fake content-box until we know it's needed to know the true value. - boxSizingNeeded = !support.boxSizingReliable() || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - valueIsBorderBox = isBorderBox, - - val = curCSS( elem, dimension, styles ), - offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); - - // Support: Firefox <=54 - // Return a confounding non-pixel value or feign ignorance, as appropriate. - if ( rnumnonpx.test( val ) ) { - if ( !extra ) { - return val; - } - val = "auto"; - } - - - // Support: IE 9 - 11 only - // Use offsetWidth/offsetHeight for when box sizing is unreliable. - // In those cases, the computed value can be trusted to be border-box. - if ( ( !support.boxSizingReliable() && isBorderBox || - - // Support: IE 10 - 11+, Edge 15 - 18+ - // IE/Edge misreport `getComputedStyle` of table rows with width/height - // set in CSS while `offset*` properties report correct values. - // Interestingly, in some cases IE 9 doesn't suffer from this issue. - !support.reliableTrDimensions() && nodeName( elem, "tr" ) || - - // Fall back to offsetWidth/offsetHeight when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - val === "auto" || - - // Support: Android <=4.1 - 4.3 only - // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) - !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && - - // Make sure the element is visible & connected - elem.getClientRects().length ) { - - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Where available, offsetWidth/offsetHeight approximate border box dimensions. - // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the - // retrieved value as a content box dimension. - valueIsBorderBox = offsetProp in elem; - if ( valueIsBorderBox ) { - val = elem[ offsetProp ]; - } - } - - // Normalize "" and auto - val = parseFloat( val ) || 0; - - // Adjust for the element's box model - return ( val + - boxModelAdjustment( - elem, - dimension, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles, - - // Provide the current computed size to request scroll gutter calculation (gh-3589) - val - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "gridArea": true, - "gridColumn": true, - "gridColumnEnd": true, - "gridColumnStart": true, - "gridRow": true, - "gridRowEnd": true, - "gridRowStart": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: {}, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append - // "px" to a few hardcoded values. - if ( type === "number" && !isCustomProp ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( _i, dimension ) { - jQuery.cssHooks[ dimension ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, dimension, extra ); - } ) : - getWidthOrHeight( elem, dimension, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = getStyles( elem ), - - // Only read styles.position if the test has a chance to fail - // to avoid forcing a reflow. - scrollboxSizeBuggy = !support.scrollboxSize() && - styles.position === "absolute", - - // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) - boxSizingNeeded = scrollboxSizeBuggy || extra, - isBorderBox = boxSizingNeeded && - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - subtract = extra ? - boxModelAdjustment( - elem, - dimension, - extra, - isBorderBox, - styles - ) : - 0; - - // Account for unreliable border-box dimensions by comparing offset* to computed and - // faking a content-box to get border and padding (gh-3699) - if ( isBorderBox && scrollboxSizeBuggy ) { - subtract -= Math.ceil( - elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - - parseFloat( styles[ dimension ] ) - - boxModelAdjustment( elem, dimension, "border", false, styles ) - - 0.5 - ); - } - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ dimension ] = value; - value = jQuery.css( elem, dimension ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( prefix !== "margin" ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && ( - jQuery.cssHooks[ tween.prop ] || - tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = Date.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 15 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY and Edge just mirrors - // the overflowX value there. - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - result.stop.bind( result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = Date.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -function classesToArray( value ) { - if ( Array.isArray( value ) ) { - return value; - } - if ( typeof value === "string" ) { - return value.match( rnothtmlwhite ) || []; - } - return []; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - classes = classesToArray( value ); - - if ( classes.length ) { - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isValidValue = type === "string" || Array.isArray( value ); - - if ( typeof stateVal === "boolean" && isValidValue ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( isValidValue ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = classesToArray( value ); - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, valueIsFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - valueIsFunction = isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( valueIsFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -support.focusin = "onfocusin" in window; - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - stopPropagationCallback = function( e ) { - e.stopPropagation(); - }; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = lastElement = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - lastElement = cur; - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( - dataPriv.get( cur, "events" ) || Object.create( null ) - )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - - if ( event.isPropagationStopped() ) { - lastElement.addEventListener( type, stopPropagationCallback ); - } - - elem[ type ](); - - if ( event.isPropagationStopped() ) { - lastElement.removeEventListener( type, stopPropagationCallback ); - } - - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - - // Handle: regular nodes (via `this.ownerDocument`), window - // (via `this.document`) & document (via `this`). - var doc = this.ownerDocument || this.document || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this.document || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = { guid: Date.now() }; - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && toType( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - if ( a == null ) { - return ""; - } - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( _i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() + " " ] = - ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) - .concat( match[ 2 ] ); - } - } - match = responseHeaders[ key.toLowerCase() + " " ]; - } - return match == null ? null : match.join( ", " ); - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 15 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available and should be processed, append data to url - if ( s.data && ( s.processData || typeof s.data === "string" ) ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + - uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Use a noop converter for missing script - if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { - s.converters[ "text script" ] = function() {}; - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( _i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - -jQuery.ajaxPrefilter( function( s ) { - var i; - for ( i in s.headers ) { - if ( i.toLowerCase() === "content-type" ) { - s.contentType = s.headers[ i ] || ""; - } - } -} ); - - -jQuery._evalUrl = function( url, options, doc ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - - // Only evaluate the response if it is successful (gh-4126) - // dataFilter is not invoked for failure responses, so using it instead - // of the default converter is kludgy but it works. - converters: { - "text script": function() {} - }, - dataFilter: function( response ) { - jQuery.globalEval( response, options, doc ); - } - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var htmlIsFunction = isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.ontimeout = - xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain or forced-by-attrs requests - if ( s.crossDomain || s.scriptAttrs ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - - - - - - - - - -
-
-
- - -
- - -

Index

- -
- A - | B - | C - | D - | E - | F - | G - | H - | I - | J - | L - | M - | O - | P - | R - | S - | T - | U - | V - | W - | X - | Z - -
-

A

- - - -
- -

B

- - - -
- -

C

- - - -
- -

D

- - - -
- -

E

- - -
- -

F

- - - -
- -

G

- - - -
- -

H

- - -
- -

I

- - - -
- -

J

- - - -
    -
  • - joy.utils.generated_library - -
  • -
  • - joy.utils.pretty_print - -
  • -
  • - joy.utils.stack - -
  • -
- -

L

- - - -
- -

M

- - -
- -

O

- - -
- -

P

- - - -
- -

R

- - - -
- -

S

- - - -
- -

T

- - - -
- -

U

- - - -
- -

V

- - - -
- -

W

- - - -
- -

X

- - -
- -

Z

- - -
- - - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/index.html b/docs/sphinx_docs/_build/html/index.html deleted file mode 100644 index ca81a00..0000000 --- a/docs/sphinx_docs/_build/html/index.html +++ /dev/null @@ -1,263 +0,0 @@ - - - - - - - - - Thun 0.4.1 Documentation — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Thun 0.4.1 Documentation

-

Thun is dialect of Joy written in Python.

-

Joy is a programming language created by Manfred von Thun that is easy to -use and understand and has many other nice properties. This Python -package implements an interpreter for a dialect of Joy that attempts to -stay very close to the spirit of Joy but does not precisely match the -behaviour of the original version(s) written in C. The main difference -between Thun and the originals, other than being written in Python, is -that it works by the “Continuation-Passing Style”.

-

Joy is:

- -

I hope that this package is useful in the sense that it provides an -additional joy interpreter (the binary in the archive from La Trobe seems -to run just fine on my modern Linux machine!) But I also hope that you -can read and understand the Python code and play with the implementation -itself.

-
-

Example Code

-

Here is an example of Joy code:

-
[[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
-
-
-

It might seem unreadable but with a little familiarity it becomes just as -legible as any other notation. Some layout helps:

-
[   [[abs] ii <=]
-    [
-        [<>] [pop !-] ||
-    ] &&
-]
-[[    !-] [[++]] [[--]] ifte dip]
-[[pop !-]  [--]   [++]  ifte    ]
-ifte
-
-
-

This function accepts two integers on the stack and increments or -decrements one of them such that the new pair of numbers is the next -coordinate pair in a square spiral (like the kind used to construct an -Ulam Spiral). For more information see Square Spiral Example Joy Code

-
-
-

Quick Start

-

Install from PyPI in the usual way:

-
$ pip install Thun
-
-
-

To start the REPL:

-
$ python -m joy
-
-
-

Continue with the introduction.

-
-
-

Project Hosted on OSDN

- -
-
-

Information on the Joy language

-

See the Wikipedia article and Kevin Albrecht’s mirror of Manfred von Thun’s original website for the Joy Programming Language for more information on the Joy language.

-

The best source (no pun intended) for learning about Joy is the -information made available at the website of La Trobe University (see the -mirror link above) which contains source code for the -original C interpreter, Joy language source code for various functions, -and a great deal of fascinating material mostly written by Von Thun on -Joy and its deeper facets as well as how to program in it and several -interesting aspects. It’s quite a treasure trove.

-
-
-

Documentation on Thun Dialect

-

The following is specific information for this dialect of Joy.

- -
-
-
-

Indices and tables

- -
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/joy.html b/docs/sphinx_docs/_build/html/joy.html deleted file mode 100644 index 2e156e8..0000000 --- a/docs/sphinx_docs/_build/html/joy.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - Joy Interpreter — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Joy Interpreter

-
-

joy.joy

-

This module implements an interpreter for a dialect of Joy that -attempts to stay very close to the spirit of Joy but does not precisely -match the behaviour of the original version(s) written in C.

-
-
-exception joy.joy.UnknownSymbolError[source]
-
- -
-
-joy.joy.interp(stack=(), dictionary=None)[source]
-

Simple REPL with no extra output, suitable for use in scripts.

-
- -
-
-joy.joy.joy(stack, expression, dictionary, viewer=None)[source]
-

Evaluate a Joy expression on a stack.

-

This function iterates through a sequence of terms which are either -literals (strings, numbers, sequences of terms) or function symbols. -Literals are put onto the stack and functions are looked up in the -dictionary and executed.

-

The viewer is a function that is called with the stack and expression -on every iteration, its return value is ignored.

-
-
Parameters
-
    -
  • stack (stack) – The stack.

  • -
  • expression (stack) – The expression to evaluate.

  • -
  • dictionary (dict) – A dict mapping names to Joy functions.

  • -
  • viewer (function) – Optional viewer function.

  • -
-
-
Return type
-

(stack, (), dictionary)

-
-
-
- -
-
-joy.joy.repl(stack=(), dictionary=None)[source]
-

Read-Evaluate-Print Loop

-

Accept input and run it on the stack, loop.

-
-
Parameters
-
    -
  • stack (stack) – The stack.

  • -
  • dictionary (dict) – A dict mapping names to Joy functions.

  • -
-
-
Return type
-

stack

-
-
-
- -
-
-joy.joy.run(text, stack, dictionary, viewer=None)[source]
-

Return the stack resulting from running the Joy code text on the stack.

-
-
Parameters
-
    -
  • text (str) – Joy code.

  • -
  • stack (stack) – The stack.

  • -
  • dictionary (dict) – A dict mapping names to Joy functions.

  • -
  • viewer (function) – Optional viewer function.

  • -
-
-
Return type
-

(stack, (), dictionary)

-
-
-
- -
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/lib.html b/docs/sphinx_docs/_build/html/lib.html deleted file mode 100644 index 4a6f7b2..0000000 --- a/docs/sphinx_docs/_build/html/lib.html +++ /dev/null @@ -1,1340 +0,0 @@ - - - - - - - - - Functions Grouped by, er, Function with Examples — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Functions Grouped by, er, Function with Examples

-
from notebook_preamble import J, V
-
-
-
-

Stack Chatter

-

This is what I like to call the functions that just rearrange things on -the stack. (One thing I want to mention is that during a hypothetical -compilation phase these “stack chatter” words effectively disappear -because we can map the logical stack locations to registers that remain -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')
-
-
-
(nothing)
-
-
-
-
-

dup dupd

-
J('1 2 3 dup')
-
-
-
1 2 3 3
-
-
-
J('1 2 3 dupd')
-
-
-
1 2 2 3
-
-
-
-
-

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.
-
-
-
[3 2 1]
-
-
-
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.
-
-
-
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.
-
-
-
6 5 4
-
-
-
-
-

pop popd popop

-
J('1 2 3 pop')
-
-
-
1 2
-
-
-
J('1 2 3 popd')
-
-
-
1 3
-
-
-
J('1 2 3 popop')
-
-
-
1
-
-
-
-
-

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<')
-
-
-
2 3 1
-
-
-
J('1 2 3 roll>')
-
-
-
3 1 2
-
-
-
-
-

swap

-
J('1 2 3 swap')
-
-
-
1 3 2
-
-
-
-
-

tuck over

-
J('1 2 3 tuck')
-
-
-
1 3 2 3
-
-
-
J('1 2 3 over')
-
-
-
1 2 3 2
-
-
-
-
-

unit quoted unquoted

-
J('1 2 3 unit')
-
-
-
1 2 [3]
-
-
-
J('1 2 3 quoted')
-
-
-
1 [2] 3
-
-
-
J('1 [2] 3 unquoted')
-
-
-
1 2 3
-
-
-
V('1 [dup] 3 unquoted')  # Unquoting evaluates.  Be aware.
-
-
-
              . 1 [dup] 3 unquoted
-            1 . [dup] 3 unquoted
-      1 [dup] . 3 unquoted
-    1 [dup] 3 . unquoted
-    1 [dup] 3 . [i] dip
-1 [dup] 3 [i] . dip
-      1 [dup] . i 3
-            1 . dup 3
-          1 1 . 3
-        1 1 3 .
-
-
-
-
-
-

List words

-
-

concat swoncat shunt

-
J('[1 2 3] [4 5 6] concat')
-
-
-
[1 2 3 4 5 6]
-
-
-
J('[1 2 3] [4 5 6] swoncat')
-
-
-
[4 5 6 1 2 3]
-
-
-
J('[1 2 3] [4 5 6] shunt')
-
-
-
[6 5 4 1 2 3]
-
-
-
-
-

cons swons uncons

-
J('1 [2 3] cons')
-
-
-
[1 2 3]
-
-
-
J('[2 3] 1 swons')
-
-
-
[1 2 3]
-
-
-
J('[1 2 3] uncons')
-
-
-
1 [2 3]
-
-
-
-
-

first second third rest

-
J('[1 2 3 4] first')
-
-
-
1
-
-
-
J('[1 2 3 4] second')
-
-
-
2
-
-
-
J('[1 2 3 4] third')
-
-
-
3
-
-
-
J('[1 2 3 4] rest')
-
-
-
[2 3 4]
-
-
-
-
-

flatten

-
J('[[1] [2 [3] 4] [5 6]] flatten')
-
-
-
[1 2 [3] 4 5 6]
-
-
-
-
-

getitem at of drop take

-

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

-
J('[10 11 12 13 14] 2 getitem')
-
-
-
12
-
-
-
J('[1 2 3 4] 0 at')
-
-
-
1
-
-
-
J('2 [1 2 3 4] of')
-
-
-
3
-
-
-
J('[1 2 3 4] 2 drop')
-
-
-
[3 4]
-
-
-
J('[1 2 3 4] 2 take')  # reverses the order
-
-
-
[2 1]
-
-
-

reverse could be defines as reverse == dup size take

-
-
-

remove

-
J('[1 2 3 1 4] 1 remove')
-
-
-
[2 3 1 4]
-
-
-
-
-

reverse

-
J('[1 2 3 4] reverse')
-
-
-
[4 3 2 1]
-
-
-
-
-

size

-
J('[1 1 1 1] size')
-
-
-
4
-
-
-
-
-

swaack

-

“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. Neither of the lists/stacks change their order.

-
J('1 2 3 [4 5 6] swaack')
-
-
-
6 5 4 [3 2 1]
-
-
-
-
-

choice select

-
J('23 9 1 choice')
-
-
-
9
-
-
-
J('23 9 0 choice')
-
-
-
23
-
-
-
J('[23 9 7] 1 select')  # select is basically getitem, should retire it?
-
-
-
9
-
-
-
J('[23 9 7] 0 select')
-
-
-
23
-
-
-
-
-

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')
-
-
-
[7 7 7]
-
-
-
-
-
-

Math words

-
-

+ add

-
J('23 9 +')
-
-
-
32
-
-
-
-
-

- sub

-
J('23 9 -')
-
-
-
14
-
-
-
-
-

* mul

-
J('23 9 *')
-
-
-
207
-
-
-
-
-

/ div floordiv truediv

-
J('23 9 /')
-
-
-
2.5555555555555554
-
-
-
J('23 -9 truediv')
-
-
-
-2.5555555555555554
-
-
-
J('23 9 div')
-
-
-
2
-
-
-
J('23 9 floordiv')
-
-
-
2
-
-
-
J('23 -9 div')
-
-
-
-3
-
-
-
J('23 -9 floordiv')
-
-
-
-3
-
-
-
-
-

% mod modulus rem remainder

-
J('23 9 %')
-
-
-
5
-
-
-
-
-

neg

-
J('23 neg -5 neg')
-
-
-
-23 5
-
-
-
-
-

pow

-
J('2 10 pow')
-
-
-
1024
-
-
-
-
-

sqr sqrt

-
J('23 sqr')
-
-
-
529
-
-
-
J('23 sqrt')
-
-
-
4.795831523312719
-
-
-
-
-

++ succ -- pred

-
J('1 ++')
-
-
-
2
-
-
-
J('1 --')
-
-
-
0
-
-
-
-
-

<< lshift >> rshift

-
J('8 1 <<')
-
-
-
16
-
-
-
J('8 1 >>')
-
-
-
4
-
-
-
-
-

average

-
J('[1 2 3 5] average')
-
-
-
2.75
-
-
-
-
-

range range_to_zero down_to_zero

-
J('5 range')
-
-
-
[4 3 2 1 0]
-
-
-
J('5 range_to_zero')
-
-
-
[0 1 2 3 4 5]
-
-
-
J('5 down_to_zero')
-
-
-
5 4 3 2 1 0
-
-
-
-
-

product

-
J('[1 2 3 5] product')
-
-
-
30
-
-
-
-
-

sum

-
J('[1 2 3 5] sum')
-
-
-
11
-
-
-
-
-

min

-
J('[1 2 3 5] min')
-
-
-
1
-
-
-
-
-

gcd

-
J('45 30 gcd')
-
-
-
15
-
-
-
-
-

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')
-
-
-
[3 2]
-
-
-
J('[23 12] least_fraction')
-
-
-
[23 12]
-
-
-
-
-
-

Logic and Comparison

-
-

? truthy

-

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

-
J('23 truthy')
-
-
-
True
-
-
-
J('[] truthy')  # Python semantics.
-
-
-
False
-
-
-
J('0 truthy')
-
-
-
False
-
-
-
? == dup truthy
-
-
-
V('23 ?')
-
-
-
        . 23 ?
-     23 . ?
-     23 . dup truthy
-  23 23 . truthy
-23 True .
-
-
-
J('[] ?')
-
-
-
[] False
-
-
-
J('0 ?')
-
-
-
0 False
-
-
-
-
-

& and

-
J('23 9 &')
-
-
-
1
-
-
-
-
-

!= <> ne

-
J('23 9 !=')
-
-
-
True
-
-
-
-
The usual suspects: - < lt - <= le
-
- = eq - > gt - >= ge - not - or
-
-
-
-

^ xor

-
J('1 1 ^')
-
-
-
0
-
-
-
J('1 0 ^')
-
-
-
1
-
-
-
-
-
-

Miscellaneous

-
-

help

-
J('[help] help')
-
-
-
Accepts a quoted symbol on the top of the stack and prints its docs.
-
-
-
-
-

parse

-
J('[parse] help')
-
-
-
Parse the string on the stack to a Joy expression.
-
-
-
J('1 "2 [3] dup" parse')
-
-
-
1 [2 [3] dup]
-
-
-
-
-

run

-

Evaluate a quoted Joy sequence.

-
J('[1 2 dup + +] run')
-
-
-
[5]
-
-
-
-
-
-

Combinators

-
-

app1 app2 app3

-
J('[app1] help')
-
-
-
Given a quoted program on TOS and anything as the second stack item run
-the program and replace the two args with the first result of the
-program.
-
-            ... x [Q] . app1
-   -----------------------------------
-      ... [x ...] [Q] . infra first
-
-
-
J('10 4 [sqr *] app1')
-
-
-
10 160
-
-
-
J('10 3 4 [sqr *] app2')
-
-
-
10 90 160
-
-
-
J('[app2] help')
-
-
-
Like app1 with two items.
-
-       ... y x [Q] . app2
------------------------------------
-   ... [y ...] [Q] . infra first
-       [x ...] [Q]   infra first
-
-
-
J('10 2 3 4 [sqr *] app3')
-
-
-
10 40 90 160
-
-
-
-
-

anamorphism

-

Given an initial value, a predicate function [P], and a generator -function [G], the anamorphism combinator creates a sequence.

-
   n [P] [G] anamorphism
----------------------------
-          [...]
-
-
-

Example, range:

-
range == [0 <=] [1 - dup] anamorphism
-
-
-
J('3 [0 <=] [1 - dup] anamorphism')
-
-
-
[2 1 0]
-
-
-
-
-

branch

-
J('3 4 1 [+] [*] branch')
-
-
-
12
-
-
-
J('3 4 0 [+] [*] branch')
-
-
-
7
-
-
-
-
-

cleave

-
... x [P] [Q] cleave
-
-
-

From the original Joy docs: “The cleave combinator expects two -quotations, and below that an item x It first executes [P], with -x on top, and saves the top result element. Then it executes -[Q], again with x, and saves the top result. Finally it restores -the stack to what it was below x and pushes the two results P(X) and -Q(X).”

-

Note that P and Q can use items from the stack freely, since the -stack (below x) is restored. cleave is a kind of parallel -primitive, and it would make sense to create a version that uses, e.g. -Python threads or something, to actually run P and Q -concurrently. The current implementation of cleave is a definition -in terms of app2:

-
cleave == [i] app2 [popd] dip
-
-
-
J('10 2 [+] [-] cleave')
-
-
-
10 12 8
-
-
-
-
-

dip dipd dipdd

-
J('1 2 3 4 5 [+] dip')
-
-
-
1 2 7 5
-
-
-
J('1 2 3 4 5 [+] dipd')
-
-
-
1 5 4 5
-
-
-
J('1 2 3 4 5 [+] dipdd')
-
-
-
3 3 4 5
-
-
-
-
-

dupdip

-

Expects a quoted program [Q] on the stack and some item under it, -dup the item and dip the quoted program under it.

-
n [Q] dupdip == n Q n
-
-
-
V('23 [++] dupdip *')  # N(N + 1)
-
-
-
        . 23 [++] dupdip *
-     23 . [++] dupdip *
-23 [++] . dupdip *
-     23 . ++ 23 *
-     24 . 23 *
-  24 23 . *
-    552 .
-
-
-
-
-

genrec primrec

-
J('[genrec] help')
-
-
-
General Recursion Combinator.
-
-                        [if] [then] [rec1] [rec2] genrec
-  ---------------------------------------------------------------------
-     [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
-
-From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun:
-"The genrec combinator takes four program parameters in addition to
-whatever data parameters it needs. Fourth from the top is an if-part,
-followed by a then-part. If the if-part yields true, then the then-part
-is executed and the combinator terminates. The other two parameters are
-the rec1-part and the rec2-part. If the if-part yields false, the
-rec1-part is executed. Following that the four program parameters and
-the combinator are again pushed onto the stack bundled up in a quoted
-form. Then the rec2-part is executed, where it will find the bundled
-form. Typically it will then execute the bundled form, either with i or
-with app2, or some other combinator."
-
-The way to design one of these is to fix your base case [then] and the
-test [if], and then treat rec1 and rec2 as an else-part "sandwiching"
-a quotation of the whole function.
-
-For example, given a (general recursive) function 'F':
-
-    F == [I] [T] [R1] [R2] genrec
-
-If the [I] if-part fails you must derive R1 and R2 from:
-
-    ... R1 [F] R2
-
-Just set the stack arguments in front, and figure out what R1 and R2
-have to do to apply the quoted [F] in the proper way.  In effect, the
-genrec combinator turns into an ifte combinator with a quoted copy of
-the original definition in the else-part:
-
-    F == [I] [T] [R1]   [R2] genrec
-      == [I] [T] [R1 [F] R2] ifte
-
-(Primitive recursive functions are those where R2 == i.
-
-    P == [I] [T] [R] primrec
-      == [I] [T] [R [P] i] ifte
-      == [I] [T] [R P] ifte
-)
-
-
-
J('3 [1 <=] [] [dup --] [i *] genrec')
-
-
-
6
-
-
-
-
-

i

-
V('1 2 3 [+ +] i')
-
-
-
            . 1 2 3 [+ +] i
-          1 . 2 3 [+ +] i
-        1 2 . 3 [+ +] i
-      1 2 3 . [+ +] i
-1 2 3 [+ +] . i
-      1 2 3 . + +
-        1 5 . +
-          6 .
-
-
-
-
-

ifte

-
[predicate] [then] [else] ifte
-
-
-
J('1 2 [1] [+] [*] ifte')
-
-
-
3
-
-
-
J('1 2 [0] [+] [*] ifte')
-
-
-
2
-
-
-
-
-

infra

-
V('1 2 3 [4 5 6] [* +] infra')
-
-
-
                    . 1 2 3 [4 5 6] [* +] infra
-                  1 . 2 3 [4 5 6] [* +] infra
-                1 2 . 3 [4 5 6] [* +] infra
-              1 2 3 . [4 5 6] [* +] infra
-      1 2 3 [4 5 6] . [* +] infra
-1 2 3 [4 5 6] [* +] . infra
-              6 5 4 . * + [3 2 1] swaack
-               6 20 . + [3 2 1] swaack
-                 26 . [3 2 1] swaack
-         26 [3 2 1] . swaack
-         1 2 3 [26] .
-
-
-
-
-

loop

-
J('[loop] help')
-
-
-
Basic loop combinator.
-
-   ... True [Q] loop
------------------------
-     ... Q [Q] loop
-
-   ... False [Q] loop
-------------------------
-          ...
-
-
-
V('3 dup [1 - dup] loop')
-
-
-
              . 3 dup [1 - dup] loop
-            3 . dup [1 - dup] loop
-          3 3 . [1 - dup] loop
-3 3 [1 - dup] . loop
-            3 . 1 - dup [1 - dup] loop
-          3 1 . - dup [1 - dup] loop
-            2 . dup [1 - dup] loop
-          2 2 . [1 - dup] loop
-2 2 [1 - dup] . loop
-            2 . 1 - dup [1 - dup] loop
-          2 1 . - dup [1 - dup] loop
-            1 . dup [1 - dup] loop
-          1 1 . [1 - dup] loop
-1 1 [1 - dup] . loop
-            1 . 1 - dup [1 - dup] loop
-          1 1 . - dup [1 - dup] loop
-            0 . dup [1 - dup] loop
-          0 0 . [1 - dup] loop
-0 0 [1 - dup] . loop
-            0 .
-
-
-
-
-

map pam

-
J('10 [1 2 3] [*] map')
-
-
-
10 [10 20 30]
-
-
-
J('10 5 [[*][/][+][-]] pam')
-
-
-
10 5 [50 2.0 15 5]
-
-
-
-
-

nullary unary binary ternary

-

Run a quoted program enforcing -arity.

-
J('1 2 3 4 5 [+] nullary')
-
-
-
1 2 3 4 5 9
-
-
-
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...
-
-
-
1 2 3 9
-
-
-
J('1 2 3 4 5 [+] ternary')
-
-
-
1 2 9
-
-
-
-
-

step

-
J('[step] help')
-
-
-
Run a quoted program on each item in a sequence.
-
-        ... [] [Q] . step
-     -----------------------
-               ... .
-
-
-       ... [a] [Q] . step
-    ------------------------
-             ... a . Q
-
-
-   ... [a b c] [Q] . step
-----------------------------------------
-             ... a . Q [b c] [Q] step
-
-The step combinator executes the quotation on each member of the list
-on top of the stack.
-
-
-
V('0 [1 2 3] [+] step')
-
-
-
              . 0 [1 2 3] [+] step
-            0 . [1 2 3] [+] step
-    0 [1 2 3] . [+] step
-0 [1 2 3] [+] . step
-      0 1 [+] . i [2 3] [+] step
-          0 1 . + [2 3] [+] step
-            1 . [2 3] [+] step
-      1 [2 3] . [+] step
-  1 [2 3] [+] . step
-      1 2 [+] . i [3] [+] step
-          1 2 . + [3] [+] step
-            3 . [3] [+] step
-        3 [3] . [+] step
-    3 [3] [+] . step
-      3 3 [+] . i
-          3 3 . +
-            6 .
-
-
-
-
-

times

-
V('3 2 1 2 [+] times')
-
-
-
            . 3 2 1 2 [+] times
-          3 . 2 1 2 [+] times
-        3 2 . 1 2 [+] times
-      3 2 1 . 2 [+] times
-    3 2 1 2 . [+] times
-3 2 1 2 [+] . times
-      3 2 1 . + 1 [+] times
-        3 3 . 1 [+] times
-      3 3 1 . [+] times
-  3 3 1 [+] . times
-        3 3 . +
-          6 .
-
-
-
-
-

b

-
J('[b] help')
-
-
-
b == [i] dip i
-
-... [P] [Q] b == ... [P] i [Q] i
-... [P] [Q] b == ... P Q
-
-
-
V('1 2 [3] [4] b')
-
-
-
            . 1 2 [3] [4] b
-          1 . 2 [3] [4] b
-        1 2 . [3] [4] b
-    1 2 [3] . [4] b
-1 2 [3] [4] . b
-        1 2 . 3 4
-      1 2 3 . 4
-    1 2 3 4 .
-
-
-
-
-

while

-
[predicate] [body] while
-
-
-
J('3 [0 >] [dup --] while')
-
-
-
3 2 1 0
-
-
-
-
-

x

-
J('[x] help')
-
-
-
x == dup i
-
-... [Q] x = ... [Q] dup i
-... [Q] x = ... [Q] [Q] i
-... [Q] x = ... [Q]  Q
-
-
-
V('1 [2] [i 3] x')  # Kind of a pointless example.
-
-
-
            . 1 [2] [i 3] x
-          1 . [2] [i 3] x
-      1 [2] . [i 3] x
-1 [2] [i 3] . x
-1 [2] [i 3] . i 3
-      1 [2] . i 3 3
-          1 . 2 3 3
-        1 2 . 3 3
-      1 2 3 . 3
-    1 2 3 3 .
-
-
-
-
-
-

void

-

Implements **Laws of Form** -*arithmetic* -over quote-only datastructures (that is, datastructures that consist -soley of containers, without strings or numbers or anything else.)

-
J('[] void')
-
-
-
False
-
-
-
J('[[]] void')
-
-
-
True
-
-
-
J('[[][[]]] void')
-
-
-
True
-
-
-
J('[[[]][[][]]] void')
-
-
-
False
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/library.html b/docs/sphinx_docs/_build/html/library.html deleted file mode 100644 index d0d4548..0000000 --- a/docs/sphinx_docs/_build/html/library.html +++ /dev/null @@ -1,1071 +0,0 @@ - - - - - - - - - Function Reference — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Function Reference

-
-

joy.library

-

This module contains the Joy function infrastructure and a library of -functions. Its main export is a Python function initialize() that -returns a dictionary of Joy functions suitable for use with the joy() -function.

-
-
-joy.library.BinaryLogicWrapper(f)[source]
-

Wrap functions that take two numbers and return a single result.

-
- -
-
-joy.library.BinaryMathWrapper(f)[source]
-

Wrap functions that take two numbers and return a single result.

-
- -
-
-class joy.library.Def(name, body)[source]
-

Definitions created by inscribe.

-
- -
-
-joy.library.FunctionWrapper(f)[source]
-

Set name attribute.

-
- -
-
-joy.library.SimpleFunctionWrapper(f)[source]
-

Wrap functions that take and return just a stack.

-
- -
-
-joy.library.UnaryBuiltinWrapper(f)[source]
-

Wrap functions that take one argument and return a single result.

-
- -
-
-joy.library.add_aliases(D, A)[source]
-

Given a dict and a iterable of (name, [alias, …]) pairs, create -additional entries in the dict mapping each alias to the named function -if it’s in the dict. Aliases for functions not in the dict are ignored.

-
- -
-
-joy.library.app1(S, expression, dictionary)[source]
-

Given a quoted program on TOS and anything as the second stack item run -the program and replace the two args with the first result of the -program.

-
     ... x [Q] . app1
------------------------------------
-   ... [x ...] [Q] . infra first
-
-
-
- -
-
-joy.library.app2(S, expression, dictionary)[source]
-

Like app1 with two items.

-
       ... y x [Q] . app2
------------------------------------
-   ... [y ...] [Q] . infra first
-       [x ...] [Q]   infra first
-
-
-
- -
-
-joy.library.app3(S, expression, dictionary)[source]
-

Like app1 with three items.

-
     ... z y x [Q] . app3
------------------------------------
-   ... [z ...] [Q] . infra first
-       [y ...] [Q]   infra first
-       [x ...] [Q]   infra first
-
-
-
- -
-
-joy.library.b(stack, expression, dictionary)[source]
-
b == [i] dip i
-
-... [P] [Q] b == ... [P] i [Q] i
-... [P] [Q] b == ... P Q
-
-
-
- -
-
-joy.library.branch(stack, expression, dictionary)[source]
-

Use a Boolean value to select one of two quoted programs to run.

-
branch == roll< choice i
-
-
-
   False [F] [T] branch
---------------------------
-      F
-
-   True [F] [T] branch
--------------------------
-         T
-
-
-
- -
-
-joy.library.choice(stack)[source]
-

Use a Boolean value to select one of two items.

-
   A B false choice
-----------------------
-   A
-
-
-   A B true choice
----------------------
-     B
-
-
-
- -
-
-joy.library.clear(stack)[source]
-

Clear everything from the stack.

-
clear == stack [pop stack] loop
-
-   ... clear
----------------
-
-
-
- -
-
-joy.library.cmp_(stack, expression, dictionary)[source]
-

cmp takes two values and three quoted programs on the stack and runs -one of the three depending on the results of comparing the two values:

-
   a b [G] [E] [L] cmp
-------------------------- a > b
-    G
-
-   a b [G] [E] [L] cmp
-------------------------- a = b
-        E
-
-   a b [G] [E] [L] cmp
-------------------------- a < b
-        L
-
-
-
- -
-
-joy.library.concat_(S)[source]
-

Concatinate the two lists on the top of the stack.

-
   [a b c] [d e f] concat
-----------------------------
-       [a b c d e f]
-
-
-
- -
-
-joy.library.cond(stack, expression, dictionary)[source]
-

This combinator works like a case statement. It expects a single quote -on the stack that must contain zero or more condition quotes and a -default quote. Each condition clause should contain a quoted predicate -followed by the function expression to run if that predicate returns -true. If no predicates return true the default function runs.

-

It works by rewriting into a chain of nested ifte expressions, e.g.:

-
      [[[B0] T0] [[B1] T1] [D]] cond
------------------------------------------
-   [B0] [T0] [[B1] [T1] [D] ifte] ifte
-
-
-
- -
-
-joy.library.dip(stack, expression, dictionary)[source]
-

The dip combinator expects a quoted program on the stack and below it -some item, it hoists the item into the expression and runs the program -on the rest of the stack.

-
   ... x [Q] dip
--------------------
-     ... Q x
-
-
-
- -
-
-joy.library.dipd(S, expression, dictionary)[source]
-

Like dip but expects two items.

-
   ... y x [Q] dip
----------------------
-     ... Q y x
-
-
-
- -
-
-joy.library.dipdd(S, expression, dictionary)[source]
-

Like dip but expects three items.

-
   ... z y x [Q] dip
------------------------
-     ... Q z y x
-
-
-
- -
-
-joy.library.disenstacken(stack)[source]
-

The disenstacken operator expects a list on top of the stack and makes that -the stack discarding the rest of the stack.

-
- -
-
-joy.library.divmod_(S)[source]
-

divmod(x, y) -> (quotient, remainder)

-

Return the tuple (x//y, x%y). Invariant: q * y + r == x.

-
- -
-
-joy.library.drop(stack)[source]
-
drop == [rest] times
-
-
-

Expects an integer and a quote on the stack and returns the quote with -n items removed off the top.

-
   [a b c d] 2 drop
-----------------------
-       [c d]
-
-
-
- -
-
-joy.library.dupdip(stack, expression, dictionary)[source]
-
[F] dupdip == dup [F] dip
-
-... a [F] dupdip
-... a dup [F] dip
-... a a   [F] dip
-... a F a
-
-
-
- -
-
-joy.library.floor(n)[source]
-

Return the floor of x as an Integral.

-

This is the largest integer <= x.

-
- -
-
-joy.library.gcd2(stack, expression, dictionary)[source]
-

Compiled GCD function.

-
- -
-
-joy.library.genrec(stack, expression, dictionary)[source]
-

General Recursion Combinator.

-
          [if] [then] [rec1] [rec2] genrec
----------------------------------------------------------------------
-   [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
-
-
-

From “Recursion Theory and Joy” (j05cmp.html) by Manfred von Thun: -“The genrec combinator takes four program parameters in addition to -whatever data parameters it needs. Fourth from the top is an if-part, -followed by a then-part. If the if-part yields true, then the then-part -is executed and the combinator terminates. The other two parameters are -the rec1-part and the rec2-part. If the if-part yields false, the -rec1-part is executed. Following that the four program parameters and -the combinator are again pushed onto the stack bundled up in a quoted -form. Then the rec2-part is executed, where it will find the bundled -form. Typically it will then execute the bundled form, either with i or -with app2, or some other combinator.”

-

The way to design one of these is to fix your base case [then] and the -test [if], and then treat rec1 and rec2 as an else-part “sandwiching” -a quotation of the whole function.

-

For example, given a (general recursive) function ‘F’:

-
F == [I] [T] [R1] [R2] genrec
-
-
-

If the [I] if-part fails you must derive R1 and R2 from:

-
... R1 [F] R2
-
-
-

Just set the stack arguments in front, and figure out what R1 and R2 -have to do to apply the quoted [F] in the proper way. In effect, the -genrec combinator turns into an ifte combinator with a quoted copy of -the original definition in the else-part:

-
F == [I] [T] [R1]   [R2] genrec
-  == [I] [T] [R1 [F] R2] ifte
-
-
-

Primitive recursive functions are those where R2 == i.

-
P == [I] [T] [R] tailrec
-  == [I] [T] [R [P] i] ifte
-  == [I] [T] [R P] ifte
-
-
-
- -
-
-joy.library.getitem(stack)[source]
-
getitem == drop first
-
-
-

Expects an integer and a quote on the stack and returns the item at the -nth position in the quote counting from 0.

-
   [a b c d] 0 getitem
--------------------------
-    a
-
-
-
- -
-
-joy.library.help_(S, expression, dictionary)[source]
-

Accepts a quoted symbol on the top of the stack and prints its docs.

-
- -
-
-joy.library.i(stack, expression, dictionary)[source]
-

The i combinator expects a quoted program on the stack and unpacks it -onto the pending expression for evaluation.

-
   [Q] i
------------
-    Q
-
-
-
- -
-
-joy.library.id_(stack)[source]
-

The identity function.

-
- -
-
-joy.library.ifte(stack, expression, dictionary)[source]
-

If-Then-Else Combinator

-
           ... [if] [then] [else] ifte
----------------------------------------------------
-   ... [[else] [then]] [...] [if] infra select i
-
-
-
-
-         ... [if] [then] [else] ifte
--------------------------------------------------------
-   ... [else] [then] [...] [if] infra first choice i
-
-
-

Has the effect of grabbing a copy of the stack on which to run the -if-part using infra.

-
- -
-
-joy.library.ii(stack, expression, dictionary)[source]
-
   ... a [Q] ii
-------------------
-    ... Q a Q
-
-
-
- -
-
-joy.library.infra(stack, expression, dictionary)[source]
-

Accept a quoted program and a list on the stack and run the program -with the list as its stack. Does not affect the rest of the stack.

-
   ... [a b c] [Q] . infra
------------------------------
-    c b a . Q [...] swaack
-
-
-
- -
-
-joy.library.initialize()[source]
-

Return a dictionary of Joy functions for use with joy().

-
- -
-
-joy.library.inscribe(function, d={'!=': <function ne>, '%': <function mod>, '&': <function and_>, '*': <function mul>, '+': <function add>, '++': <function succ>, '-': <function sub>, '--': <function pred>, '/': <function floordiv>, '//': <function floordiv>, '/floor': <function floordiv>, '<': <function lt>, '<<': <function lshift>, '<=': <function le>, '<>': <function ne>, '=': <function eq>, '>': <function gt>, '>=': <function ge>, '>>': <function rshift>, '^': <function xor>, '_Tree_add_Ee': <function _Tree_add_Ee>, '_Tree_delete_R0': <function _Tree_delete_R0>, '_Tree_delete_clear_stuff': <function _Tree_delete_clear_stuff>, '_Tree_get_E': <function _Tree_get_E>, 'abs': <function abs>, 'add': <function add>, 'and': <function and_>, 'app1': <function app1>, 'app2': <function app2>, 'app3': <function app3>, 'at': <function getitem>, 'b': <function b>, 'bool': <function bool>, 'branch': <function branch>, 'ccons': <function ccons>, 'choice': <function choice>, 'clear': <function clear>, 'cmp': <function cmp_>, 'concat': <function concat_>, 'cond': <function cond>, 'cons': <function cons>, 'dip': <function dip>, 'dipd': <function dipd>, 'dipdd': <function dipdd>, 'disenstacken': <function disenstacken>, 'div': <function floordiv>, 'divmod': <function divmod_>, 'drop': <function drop>, 'dup': <function dup>, 'dupd': <function dupd>, 'dupdd': <function dupdd>, 'dupdip': <function dupdip>, 'eq': <function eq>, 'first': <function first>, 'first_two': <function first_two>, 'floor': <function floor>, 'floordiv': <function floordiv>, 'fourth': <function fourth>, 'gcd2': <function gcd2>, 'ge': <function ge>, 'genrec': <function genrec>, 'getitem': <function getitem>, 'gt': <function gt>, 'help': <function help_>, 'i': <function i>, 'id': <function id_>, 'ifte': <function ifte>, 'ii': <function ii>, 'infra': <function infra>, 'inscribe': <function inscribe_>, 'le': <function le>, 'loop': <function loop>, 'lshift': <function lshift>, 'lt': <function lt>, 'map': <function map_>, 'max': <function max_>, 'min': <function min_>, 'mod': <function mod>, 'modulus': <function mod>, 'mul': <function mul>, 'ne': <function ne>, 'neg': <function neg>, 'not': <function not_>, 'or': <function or_>, 'over': <function over>, 'pick': <function getitem>, 'pm': <function pm>, 'pop': <function pop>, 'popd': <function popd>, 'popdd': <function popdd>, 'popop': <function popop>, 'popopd': <function popopd>, 'popopdd': <function popopdd>, 'pow': <function pow>, 'pred': <function pred>, 'primrec': <function primrec>, 'rem': <function mod>, 'remainder': <function mod>, 'remove': <function remove>, 'rest': <function rest>, 'reverse': <function reverse>, 'roll<': <function rolldown>, 'roll>': <function rollup>, 'rolldown': <function rolldown>, 'rollup': <function rollup>, 'round': <function round>, 'rrest': <function rrest>, 'rshift': <function rshift>, 'second': <function second>, 'select': <function select>, 'sharing': <function sharing>, 'shunt': <function shunt>, 'sort': <function sort_>, 'sqrt': <function sqrt>, 'stack': <function stack>, 'step': <function step>, 'stuncons': <function stuncons>, 'stununcons': <function stununcons>, 'sub': <function sub>, 'succ': <function succ>, 'sum': <function sum_>, 'swaack': <function swaack>, 'swap': <function swap>, 'swons': <function swons>, 'take': <function take>, 'third': <function third>, 'times': <function times>, 'truthy': <function bool>, 'tuck': <function tuck>, 'uncons': <function uncons>, 'unique': <function unique>, 'unit': <function unit>, 'unswons': <function unswons>, 'void': <function void>, 'warranty': <function warranty>, 'words': <function words>, 'x': <function x>, 'xor': <function xor>, 'zip': <function zip_>, '•': <function id_>})[source]
-

A decorator to inscribe functions into the default dictionary.

-
- -
-
-joy.library.inscribe_(stack, expression, dictionary)[source]
-

Create a new Joy function definition in the Joy dictionary. A -definition is given as a quote with a name followed by a Joy -expression. for example:

-
-

[sqr dup mul] inscribe

-
-
- -
-
-joy.library.loop(stack, expression, dictionary)[source]
-

Basic loop combinator.

-
   ... True [Q] loop
------------------------
-      ... Q [Q] loop
-
-   ... False [Q] loop
-------------------------
-      ...
-
-
-
- -
-
-joy.library.map_(S, expression, dictionary)[source]
-

Run the quoted program on TOS on the items in the list under it, push a -new list with the results in place of the program and original list.

-
- -
-
-joy.library.max_(S)[source]
-

Given a list find the maximum.

-
- -
-
-joy.library.min_(S)[source]
-

Given a list find the minimum.

-
- -
-
-joy.library.pm(stack)[source]
-

Plus or minus

-
   a b pm
--------------
-   a+b a-b
-
-
-
- -
-
-joy.library.pred(S)[source]
-

Decrement TOS.

-
- -
-
-joy.library.primrec(stack, expression, dictionary)[source]
-

From the “Overview of the language JOY”:

-

> The primrec combinator expects two quoted programs in addition to a -data parameter. For an integer data parameter it works like this: If -the data parameter is zero, then the first quotation has to produce -the value to be returned. If the data parameter is positive then the -second has to combine the data parameter with the result of applying -the function to its predecessor.:

-
5  [1]  [*]  primrec
-
-
-

> Then primrec tests whether the top element on the stack (initially -the 5) is equal to zero. If it is, it pops it off and executes one of -the quotations, the [1] which leaves 1 on the stack as the result. -Otherwise it pushes a decremented copy of the top element and -recurses. On the way back from the recursion it uses the other -quotation, [*], to multiply what is now a factorial on top of the -stack by the second element on the stack.:

-
n [Base] [Recur] primrec
-
-   0 [Base] [Recur] primrec
-------------------------------
-      Base
-
-     n [Base] [Recur] primrec
------------------------------------------- n > 0
-   n (n-1) [Base] [Recur] primrec Recur
-
-
-
- -
-
-joy.library.remove(S)[source]
-

Expects an item on the stack and a quote under it and removes that item -from the the quote. The item is only removed once. If the list is -empty or the item isn’t in the list then the list is unchanged.

-
   [1 2 3 1] 1 remove
-------------------------
-     [2 3 1]
-
-
-
- -
-
-joy.library.reverse(S)[source]
-

Reverse the list on the top of the stack.

-
reverse == [] swap shunt
-
-
-
- -
-
-joy.library.select(stack)[source]
-

Use a Boolean value to select one of two items from a sequence.

-
   [A B] false select
-------------------------
-    A
-
-
-   [A B] true select
------------------------
-      B
-
-
-

The sequence can contain more than two items but not fewer. -Currently Python semantics are used to evaluate the “truthiness” of the -Boolean value (so empty string, zero, etc. are counted as false, etc.)

-
- -
-
-joy.library.sharing(stack, expression, dictionary)[source]
-

Print redistribution information.

-
- -
-
-joy.library.shunt(stack)[source]
-

Like concat but reverses the top list into the second.

-
shunt == [swons] step == reverse swap concat
-
-   [a b c] [d e f] shunt
----------------------------
-       [f e d a b c] 
-
-
-
- -
-
-joy.library.sort_(S)[source]
-

Given a list return it sorted.

-
- -
-
-joy.library.sqrt(a)[source]
-

Return the square root of the number a. -Negative numbers return complex roots.

-
- -
-
-joy.library.step(S, expression, dictionary)[source]
-

Run a quoted program on each item in a sequence.

-
   ... [] [Q] . step
------------------------
-      ... .
-
-
-   ... [a] [Q] . step
-------------------------
-     ... a . Q
-
-
-   ... [a b c] [Q] . step
-----------------------------------------
-         ... a . Q [b c] [Q] step
-
-
-

The step combinator executes the quotation on each member of the list -on top of the stack.

-
- -
-
-joy.library.succ(S)[source]
-

Increment TOS.

-
- -
-
-joy.library.sum_(S)[source]
-

Given a quoted sequence of numbers return the sum.

-
sum == 0 swap [+] step
-
-
-
- -
-
-joy.library.take(stack)[source]
-

Expects an integer and a quote on the stack and returns the quote with -just the top n items in reverse order (because that’s easier and you can -use reverse if needed.)

-
   [a b c d] 2 take
-----------------------
-       [b a]
-
-
-
- -
-
-joy.library.times(stack, expression, dictionary)[source]
-

times == [– dip] cons [swap] infra [0 >] swap while pop

-
   ... n [Q] . times
----------------------  w/ n <= 0
-     ... .
-
-
-   ... 1 [Q] . times
------------------------
-     ... . Q
-
-
-   ... n [Q] . times
--------------------------------------  w/ n > 1
-     ... . Q (n - 1) [Q] times
-
-
-
- -
-
-joy.library.unique(S)[source]
-

Given a list remove duplicate items.

-
- -
-
-joy.library.void(stack)[source]
-

True if the form on TOS is void otherwise False.

-
- -
-
-joy.library.warranty(stack, expression, dictionary)[source]
-

Print warranty information.

-
- -
-
-joy.library.words(stack, expression, dictionary)[source]
-

Print all the words in alphabetical order.

-
- -
-
-joy.library.x(stack, expression, dictionary)[source]
-
x == dup i
-
-... [Q] x = ... [Q] dup i
-... [Q] x = ... [Q] [Q] i
-... [Q] x = ... [Q]  Q
-
-
-
- -
-
-joy.library.zip_(S)[source]
-

Replace the two lists on the top of the stack with a list of the pairs -from each list. The smallest list sets the length of the result list.

-
- -
-
-

Auto-generated Functions

-
-
-joy.utils.generated_library.ccons(stack)[source]
-
(a2 a1 [...1] -- [a2 a1 ...1])
-
-
-
- -
-
-joy.utils.generated_library.cons(stack)[source]
-
(a1 [...0] -- [a1 ...0])
-
-
-
- -
-
-joy.utils.generated_library.dup(stack)[source]
-
(a1 -- a1 a1)
-
-
-
- -
-
-joy.utils.generated_library.dupd(stack)[source]
-
(a2 a1 -- a2 a2 a1)
-
-
-
- -
-
-joy.utils.generated_library.dupdd(stack)[source]
-
(a3 a2 a1 -- a3 a3 a2 a1)
-
-
-
- -
-
-joy.utils.generated_library.first(stack)[source]
-
([a1 ...1] -- a1)
-
-
-
- -
-
-joy.utils.generated_library.first_two(stack)[source]
-
([a1 a2 ...1] -- a1 a2)
-
-
-
- -
-
-joy.utils.generated_library.fourth(stack)[source]
-
([a1 a2 a3 a4 ...1] -- a4)
-
-
-
- -
-
-joy.utils.generated_library.over(stack)[source]
-
(a2 a1 -- a2 a1 a2)
-
-
-
- -
-
-joy.utils.generated_library.pop(stack)[source]
-
(a1 --)
-
-
-
- -
-
-joy.utils.generated_library.popd(stack)[source]
-
(a2 a1 -- a1)
-
-
-
- -
-
-joy.utils.generated_library.popdd(stack)[source]
-
(a3 a2 a1 -- a2 a1)
-
-
-
- -
-
-joy.utils.generated_library.popop(stack)[source]
-
(a2 a1 --)
-
-
-
- -
-
-joy.utils.generated_library.popopd(stack)[source]
-
(a3 a2 a1 -- a1)
-
-
-
- -
-
-joy.utils.generated_library.popopdd(stack)[source]
-
(a4 a3 a2 a1 -- a2 a1)
-
-
-
- -
-
-joy.utils.generated_library.rest(stack)[source]
-
([a1 ...0] -- [...0])
-
-
-
- -
-
-joy.utils.generated_library.rolldown(stack)[source]
-
(a1 a2 a3 -- a2 a3 a1)
-
-
-
- -
-
-joy.utils.generated_library.rollup(stack)[source]
-
(a1 a2 a3 -- a3 a1 a2)
-
-
-
- -
-
-joy.utils.generated_library.rrest(stack)[source]
-
([a1 a2 ...1] -- [...1])
-
-
-
- -
-
-joy.utils.generated_library.second(stack)[source]
-
([a1 a2 ...1] -- a2)
-
-
-
- -
-
-joy.utils.generated_library.stack(stack)[source]
-
(... -- ... [...])
-
-
-
- -
-
-joy.utils.generated_library.stuncons(stack)[source]
-
(... a1 -- ... a1 a1 [...])
-
-
-
- -
-
-joy.utils.generated_library.stununcons(stack)[source]
-
(... a2 a1 -- ... a2 a1 a1 a2 [...])
-
-
-
- -
-
-joy.utils.generated_library.swaack(stack)[source]
-
([...1] -- [...0])
-
-
-
- -
-
-joy.utils.generated_library.swap(stack)[source]
-
(a1 a2 -- a2 a1)
-
-
-
- -
-
-joy.utils.generated_library.swons(stack)[source]
-
([...1] a1 -- [a1 ...1])
-
-
-
- -
-
-joy.utils.generated_library.third(stack)[source]
-
([a1 a2 a3 ...1] -- a3)
-
-
-
- -
-
-joy.utils.generated_library.tuck(stack)[source]
-
(a2 a1 -- a1 a2 a1)
-
-
-
- -
-
-joy.utils.generated_library.uncons(stack)[source]
-
([a1 ...0] -- a1 [...0])
-
-
-
- -
-
-joy.utils.generated_library.unit(stack)[source]
-
(a1 -- [a1 ])
-
-
-
- -
-
-joy.utils.generated_library.unswons(stack)[source]
-
([a1 ...1] -- [...1] a1)
-
-
-
- -
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Categorical.html b/docs/sphinx_docs/_build/html/notebooks/Categorical.html deleted file mode 100644 index 7b2020f..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Categorical.html +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - Categorical Programming — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Categorical Programming

-

DRAFT

-

Categorical

-

In Manfred von Thun’s article Joy compared with other functional languages he asks, “Could the language of categories be used for writing programs? Any lambda expression can be translated into a categorical expression, so the language of categories is expressively complete. But this does not make it a suitable language for writing programs. As it stands it is a very low-level language.”

-

In Compiling to categories Conal Elliott give a taste of what this might mean.

-
-

It is well-known that the simply typed lambda-calculus is modeled by any cartesian closed category (CCC). This correspondence suggests giving typed functional programs a variety of interpretations, each corresponding to a different category. A convenient way to realize this idea is as a collection of meaning-preserving transformations added to an existing compiler, such as GHC for Haskell. This paper describes such an implementation and demonstrates its use for a variety of interpretations including hardware circuits, automatic differentiation, incremental computation, and interval analysis. Each such interpretation is a category easily defined in Haskell (outside of the compiler). The general technique appears to provide a compelling alternative to deeply embedded domain-specific languages.

-
-

What he’s doing is translating lambda forms into a kind of “point-free” style that is very close to Joy code (although more verbose) and then showing how to instantiate that code over different categories to get several different kinds of program out of the same code.

-
- - -
- -
-
- -
-
- - - - \ No newline at end of file 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 deleted file mode 100644 index fc0fd9c..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Derivatives_of_Regular_Expressions.html +++ /dev/null @@ -1,935 +0,0 @@ - - - - - - - - - ∂RE — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

∂RE

-
-

Brzozowski’s Derivatives of Regular Expressions

-

Legend:

-
∧ intersection
-∨ union
-∘ concatenation (see below)
-¬ complement
-ϕ empty set (aka ∅)
-λ singleton set containing just the empty string
-I set of all letters in alphabet
-
-
-

Derivative of a set R of strings and a string a:

-
∂a(R)
-
-∂a(a) → λ
-∂a(λ) → ϕ
-∂a(ϕ) → ϕ
-∂a(¬a) → ϕ
-∂a(R*) → ∂a(R)∘R*
-∂a(¬R) → ¬∂a(R)
-∂a(R∘S) → ∂a(R)∘S ∨ δ(R)∘∂a(S)
-∂a(R ∧ S) → ∂a(R) ∧ ∂a(S)
-∂a(R ∨ S) → ∂a(R) ∨ ∂a(S)
-
-∂ab(R) = ∂b(∂a(R))
-
-
-

Auxiliary predicate function δ (I call it nully) returns either -λ if λ R or ϕ otherwise:

-
δ(a) → ϕ
-δ(λ) → λ
-δ(ϕ) → ϕ
-δ(R*) → λ
-δ(¬R) δ(R)≟ϕ → λ
-δ(¬R) δ(R)≟λ → ϕ
-δ(R∘S) → δ(R) ∧ δ(S)
-δ(R ∧ S) → δ(R) ∧ δ(S)
-δ(R ∨ S) → δ(R) ∨ δ(S)
-
-
-

Some rules we will use later for “compaction”:

-
R ∧ ϕ = ϕ ∧ R = ϕ
-
-R ∧ I = I ∧ R = R
-
-R ∨ ϕ = ϕ ∨ R = R
-
-R ∨ I = I ∨ R = I
-
-R∘ϕ = ϕ∘R = ϕ
-
-R∘λ = λ∘R = R
-
-
-

Concatination of sets: for two sets A and B the set A∘B is defined as:

-

{a∘b for a in A for b in B}

-

E.g.:

-

{‘a’, ‘b’}∘{‘c’, ‘d’} → {‘ac’, ‘ad’, ‘bc’, ‘bd’}

-
-
-

Implementation

-
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({''}) # λ
-
-
-
-
-

Two-letter Alphabet

-

I’m only going to use two symbols (at first) becaase this is enough to -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'})
-
-
-
-
-

Representing Regular Expressions

-

To represent REs in Python I’m going to use tagged tuples. A regular -expression is one of:

-
O
-l
-(KSTAR, R)
-(NOT, R)
-(AND, R, S)
-(CONS, R, S)
-(OR, R, S)
-
-
-

Where R and S stand for regular expressions.

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

Because they are formed of frozenset, tuple and str objects -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
-
-
-
-
-

I

-

Match anything. Often spelled “.”

-
I = (0|1)*
-
-
-
I = (KSTAR, (OR, O, l))
-
-
-
print stringy(I)
-
-
-
.
-
-
-
-
-

(.111.) & (.01 + 11*)'

-

The example expression from Brzozowski:

-
(.111.) & (.01 + 11*)'
-   a    &  (b  +  c)'
-
-
-

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)))
-
-
-
print stringy(it)
-
-
-
(.111.) & ((.01 | 11*)')
-
-
-
-
-

nully()

-

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

-
def nully(R):
-    '''
-    δ - Return λ if λ ⊆ R otherwise ϕ.
-    '''
-
-    # δ(a) → ϕ
-    # δ(ϕ) → ϕ
-    if R in syms or R == phi:
-        return phi
-
-    # δ(λ) → λ
-    if R == y:
-        return y
-
-    tag = R[0]
-
-    # δ(R*) → λ
-    if tag == KSTAR:
-        return 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
-
-
-
-
-

No “Compaction”

-

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 derv(R):
-
-        # ∂a(a) → λ
-        if R == {symbol}:
-            return y
-
-        # ∂a(λ) → ϕ
-        # ∂a(ϕ) → ϕ
-        # ∂a(¬a) → ϕ
-        if R == y or R == phi or R in syms:
-            return phi
-
-        tag = R[0]
-
-        # ∂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]))
-
-        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) ∧ ∂a(S)
-        # ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S)
-        return (tag, derv(r), derv(s))
-
-    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)
-        )
-
-
-

An elegant symmetry.

-
# 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∘ϕ = ϕ∘R = ϕ
-_cons = curry(_compaction_rule, CONS, y, phi)
-
-
-
-
-

Memoizing

-

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

With “Compaction”

-

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

-
def D_compaction(symbol):
-
-    @Memo
-    def derv(R):
-
-        # ∂a(a) → λ
-        if R == {symbol}:
-            return y
-
-        # ∂a(λ) → ϕ
-        # ∂a(ϕ) → ϕ
-        # ∂a(¬a) → ϕ
-        if R == y or R == phi or R in syms:
-            return phi
-
-        tag = R[0]
-
-        # ∂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]))
-
-        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) ∧ ∂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
-
-
-
-
-
-

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
-
-
-
(.111.) & ((.01 | 11*)')
-
-92 / 122
-92 / 122
-
-(.01)'
-(.01 | 1)'
-(.01 | ^)'
-(.01 | 1*)'
-(.111.) & ((.01 | 1)')
-(.111. | 11.) & ((.01 | ^)')
-(.111. | 11. | 1.) & ((.01)')
-(.111. | 11.) & ((.01 | 1*)')
-(.111. | 11. | 1.) & ((.01 | 1*)')
-
-
-

Should match:

-
(.111.) & ((.01 | 11*)')
-
-92 / 122
-92 / 122
-
-(.01     )'
-(.01 | 1 )'
-(.01 | ^ )'
-(.01 | 1*)'
-(.111.)            & ((.01 | 1 )')
-(.111. | 11.)      & ((.01 | ^ )')
-(.111. | 11.)      & ((.01 | 1*)')
-(.111. | 11. | 1.) & ((.01     )')
-(.111. | 11. | 1.) & ((.01 | 1*)')
-
-
-
-
-

Larger Alphabets

-

We could parse larger alphabets by defining patterns for e.g. each byte -of the ASCII code. Or we can generalize this code. If you study the code -above you’ll see that we never use the “set-ness” of the symbols O -and l. The only time Python set operators (& and |) appear -is in the nully() function, and there they operate on (recursively -computed) outputs of that function, never O and l.

-

What if we try:

-
(OR, O, l)
-
-∂1((OR, O, l))
-                            ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S)
-∂1(O) ∨ ∂1(l)
-                            ∂a(¬a) → ϕ
-ϕ ∨ ∂1(l)
-                            ∂a(a) → λ
-ϕ ∨ λ
-                            ϕ ∨ R = R
-λ
-
-
-

And compare it to:

-
{'0', '1')
-
-∂1({'0', '1'))
-                            ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S)
-∂1({'0')) ∨ ∂1({'1'))
-                            ∂a(¬a) → ϕ
-ϕ ∨ ∂1({'1'))
-                            ∂a(a) → λ
-ϕ ∨ λ
-                            ϕ ∨ R = R
-λ
-
-
-

This suggests that we should be able to alter the functions above to -detect sets and deal with them appropriately. Exercise for the Reader -for now.

-
-
-

State Machine

-

We can drive the regular expressions to flesh out the underlying state -machine transition table.

-
.111. & (.01 + 11*)'
-
-
-

Says, “Three or more 1’s and not ending in 01 nor composed of all 1’s.”

-
-State Machine Graph
-

State Machine Graph

-
-
-

Start at a and follow the transition arrows according to their -labels. Accepting states have a double outline. (Graphic generated with -Dot from Graphviz.) You’ll see that only -paths that lead to one of the accepting states will match the regular -expression. All other paths will terminate at one of the non-accepting -states.

-

There’s a happy path to g along 111:

-
a→c→e→g
-
-
-

After you reach g you’re stuck there eating 1’s until you see a 0, -which takes you to the i→j→i|i→j→h→i “trap”. You can’t reach any -other states from those two loops.

-

If you see a 0 before you see 111 you will reach b, which forms -another “trap” with d and f. The only way out is another happy -path along 111 to h:

-
b→d→f→h
-
-
-

Once you have reached h you can see as many 1’s or as many 0’ in a -row and still be either still at h (for 1’s) or move to i (for -0’s). If you find yourself at i you can see as many 0’s, or -repetitions of 10, as there are, but if you see just a 1 you move to -j.

-
-

RE to FSM

-

So how do we get the state machine from the regular expression?

-

It turns out that each RE is effectively a state, and each arrow points -to the derivative RE in respect to the arrow’s symbol.

-

If we label the initial RE a, we can say:

-
a --0--> ∂0(a)
-a --1--> ∂1(a)
-
-
-

And so on, each new unique RE is a new state in the FSM table.

-

Here are the derived REs at each state:

-
a = (.111.) & ((.01 | 11*)')
-b = (.111.) & ((.01 | 1)')
-c = (.111. | 11.) & ((.01 | 1*)')
-d = (.111. | 11.) & ((.01 | ^)')
-e = (.111. | 11. | 1.) & ((.01 | 1*)')
-f = (.111. | 11. | 1.) & ((.01)')
-g = (.01 | 1*)'
-h = (.01)'
-i = (.01 | 1)'
-j = (.01 | ^)'
-
-
-

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
-
-
-
d0, d1 = D_compaction('0'), D_compaction('1')
-
-
-
-
-

explore()

-
def explore(re):
-
-    # Don't have more than 26 states...
-    names = defaultdict(iter(ascii_lowercase).next)
-
-    table, accepting = dict(), set()
-
-    to_check = {re}
-    while to_check:
-
-        re = to_check.pop()
-        state_name = names[re]
-
-        if (state_name, 0) in table:
-            continue
-
-        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)
-
-    return table, accepting
-
-
-
table, accepting = explore(it)
-table
-
-
-
{('a', 0): 'b',
- ('a', 1): 'c',
- ('b', 0): 'b',
- ('b', 1): 'd',
- ('c', 0): 'b',
- ('c', 1): 'e',
- ('d', 0): 'b',
- ('d', 1): 'f',
- ('e', 0): 'b',
- ('e', 1): 'g',
- ('f', 0): 'b',
- ('f', 1): 'h',
- ('g', 0): 'i',
- ('g', 1): 'g',
- ('h', 0): 'i',
- ('h', 1): 'h',
- ('i', 0): 'i',
- ('i', 1): 'j',
- ('j', 0): 'i',
- ('j', 1): 'h'}
-
-
-
accepting
-
-
-
{'h', 'i'}
-
-
-
-
-

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
-}
-'''
-
-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())
-          )
-        )
-
-
-
print make_graph(table, accepting)
-
-
-
digraph finite_state_machine {
-  rankdir=LR;
-  size="8,5"
-  node [shape = doublecircle]; i h;
-  node [shape = circle];
-  a -> b [ label = "0" ];
-  a -> c [ label = "1" ];
-  b -> b [ label = "0" ];
-  b -> d [ label = "1" ];
-  c -> b [ label = "0" ];
-  c -> e [ label = "1" ];
-  d -> b [ label = "0" ];
-  d -> f [ label = "1" ];
-  e -> b [ label = "0" ];
-  e -> g [ label = "1" ];
-  f -> b [ label = "0" ];
-  f -> h [ label = "1" ];
-  g -> i [ label = "0" ];
-  g -> g [ label = "1" ];
-  h -> i [ label = "0" ];
-  h -> h [ label = "1" ];
-  i -> i [ label = "0" ];
-  i -> j [ label = "1" ];
-  j -> i [ label = "0" ];
-  j -> h [ label = "1" ];
-}
-
-
-
-
-

Drive a FSM

-

There are lots of FSM libraries already. Once you have the state -transition table they should all be straightforward to use. State -Machine code is very simple. Just for fun, here is an implementation in -Python that imitates what “compiled” FSM code might look like in an -“unrolled” form. Most FSM code uses a little driver loop and a table -datastructure, the code below instead acts like JMP instructions -(“jump”, or GOTO in higher-level-but-still-low-level languages) to -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
-
-
-
-
-

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))
-
-
-def _1(I):
-    '''Loop on ones.'''
-    while getch(I): pass
-
-
-def _0(I):
-    '''Loop on zeros.'''
-    while not getch(I): pass
-
-
-
-
-

A Finite State Machine

-

With those preliminaries out of the way, from the state table of -.111. & (.01 + 11*)' we can immediately write down state machine -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
-
-
-

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})
-
-
-
for n in range(2**5):
-    s = bin(n)[2:]
-    print '%05s' % s, acceptable(s)
-
-
-
    0 False
-    1 False
-   10 False
-   11 False
-  100 False
-  101 False
-  110 False
-  111 False
- 1000 False
- 1001 False
- 1010 False
- 1011 False
- 1100 False
- 1101 False
- 1110 True
- 1111 False
-10000 False
-10001 False
-10010 False
-10011 False
-10100 False
-10101 False
-10110 False
-10111 True
-11000 False
-11001 False
-11010 False
-11011 False
-11100 True
-11101 False
-11110 True
-11111 False
-
-
-
-
-
-
-

Reversing the Derivatives to Generate Matching Strings

-

(UNFINISHED) Brzozowski also shewed how to go from the state machine to -strings and expressions…

-

Each of these states is just a name for a Brzozowskian RE, and so, other -than the initial state a, they can can be described in terms of the -derivative-with-respect-to-N of some other state/RE:

-
c = d1(a)
-b = d0(a)
-b = d0(c)
-...
-i = d0(j)
-j = d1(i)
-
-
-

Consider:

-
c = d1(a)
-b = d0(c)
-
-
-

Substituting:

-
b = d0(d1(a))
-
-
-

Unwrapping:

-
b = d10(a)
-
-
-

’’’

-
j = d1(d0(j))
-
-
-

Unwrapping:

-
j = d1(d0(j)) = d01(j)
-
-
-

We have a loop or “fixed point”.

-
j = d01(j) = d0101(j) = d010101(j) = ...
-
-
-

hmm…

-
j = (01)*
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Developing.html b/docs/sphinx_docs/_build/html/notebooks/Developing.html deleted file mode 100644 index 6a2808e..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Developing.html +++ /dev/null @@ -1,755 +0,0 @@ - - - - - - - - - Developing a Program in Joy — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Developing a Program in Joy

-

As an example of developing a program in Joy let’s take the first problem from the Project Euler website.

-
-

Project Euler, first problem: “Multiples of 3 and 5”

-
-

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

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')
-
-
-
V('80 P')
-
-
-
             . 80 P
-          80 . P
-          80 . [3 % not] dupdip 5 % not or
-80 [3 % not] . dupdip 5 % not or
-          80 . 3 % not 80 5 % not or
-        80 3 . % not 80 5 % not or
-           2 . not 80 5 % not or
-       False . 80 5 % not or
-    False 80 . 5 % not or
-  False 80 5 . % not or
-     False 0 . not or
-  False True . or
-        True .
-
-
-

Given the predicate function P a suitable program is:

-
PE1 == 1000 range [P] filter sum
-
-
-

This function generates a list of the integers from 0 to 999, filters -that list by P, and then sums the result.

-

Logically this is fine, but pragmatically we are doing more work than we -should be; we generate one thousand integers but actually use less than -half of them. A better solution would be to generate just the multiples -we want to sum, and to add them as we go rather than storing them and -and summing them at the end.

-
-
-

Generate just the multiples

-

At first I had the idea to use two counters and increase them by three -and five, respectively. This way we only generate the terms that we -actually want to sum. We have to proceed by incrementing the counter -that is lower, or if they are equal, the three counter, and we have to -take care not to double add numbers like 15 that are multiples of both -three and five.

-

This seemed a little clunky, so I tried a different approach.

-

Consider the first few terms in the series:

-
3 5 6 9 10 12 15 18 20 21 ...
-
-
-

Subtract each number from the one after it (subtracting 0 from 3):

-
3 5 6 9 10 12 15 18 20 21 24 25 27 30 ...
-0 3 5 6  9 10 12 15 18 20 21 24 25 27 ...
--------------------------------------------
-3 2 1 3  1  2  3  3  2  1  3  1  2  3 ...
-
-
-

You get this lovely repeating palindromic sequence:

-
3 2 1 3 1 2 3
-
-
-

To make a counter that increments by factors of 3 and 5 you just add -these differences to the counter one-by-one in a loop.

-

To make use of this sequence to increment a counter and sum terms as we -go we need a function that will accept the sum, the counter, and the -next term to add, and that adds the term to the counter and a copy of -the counter to the running sum. This function will do that:

-
PE1.1 == + [+] dupdip
-
-
-
define('PE1.1 == + [+] dupdip')
-
-
-
V('0 0 3 PE1.1')
-
-
-
        . 0 0 3 PE1.1
-      0 . 0 3 PE1.1
-    0 0 . 3 PE1.1
-  0 0 3 . PE1.1
-  0 0 3 . + [+] dupdip
-    0 3 . [+] dupdip
-0 3 [+] . dupdip
-    0 3 . + 3
-      3 . 3
-    3 3 .
-
-
-
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
-                          0 . 0 [3 2 1 3 1 2 3] [PE1.1] step
-                        0 0 . [3 2 1 3 1 2 3] [PE1.1] step
-        0 0 [3 2 1 3 1 2 3] . [PE1.1] step
-0 0 [3 2 1 3 1 2 3] [PE1.1] . step
-              0 0 3 [PE1.1] . i [2 1 3 1 2 3] [PE1.1] step
-                      0 0 3 . PE1.1 [2 1 3 1 2 3] [PE1.1] step
-                      0 0 3 . + [+] dupdip [2 1 3 1 2 3] [PE1.1] step
-                        0 3 . [+] dupdip [2 1 3 1 2 3] [PE1.1] step
-                    0 3 [+] . dupdip [2 1 3 1 2 3] [PE1.1] step
-                        0 3 . + 3 [2 1 3 1 2 3] [PE1.1] step
-                          3 . 3 [2 1 3 1 2 3] [PE1.1] step
-                        3 3 . [2 1 3 1 2 3] [PE1.1] step
-          3 3 [2 1 3 1 2 3] . [PE1.1] step
-  3 3 [2 1 3 1 2 3] [PE1.1] . step
-              3 3 2 [PE1.1] . i [1 3 1 2 3] [PE1.1] step
-                      3 3 2 . PE1.1 [1 3 1 2 3] [PE1.1] step
-                      3 3 2 . + [+] dupdip [1 3 1 2 3] [PE1.1] step
-                        3 5 . [+] dupdip [1 3 1 2 3] [PE1.1] step
-                    3 5 [+] . dupdip [1 3 1 2 3] [PE1.1] step
-                        3 5 . + 5 [1 3 1 2 3] [PE1.1] step
-                          8 . 5 [1 3 1 2 3] [PE1.1] step
-                        8 5 . [1 3 1 2 3] [PE1.1] step
-            8 5 [1 3 1 2 3] . [PE1.1] step
-    8 5 [1 3 1 2 3] [PE1.1] . step
-              8 5 1 [PE1.1] . i [3 1 2 3] [PE1.1] step
-                      8 5 1 . PE1.1 [3 1 2 3] [PE1.1] step
-                      8 5 1 . + [+] dupdip [3 1 2 3] [PE1.1] step
-                        8 6 . [+] dupdip [3 1 2 3] [PE1.1] step
-                    8 6 [+] . dupdip [3 1 2 3] [PE1.1] step
-                        8 6 . + 6 [3 1 2 3] [PE1.1] step
-                         14 . 6 [3 1 2 3] [PE1.1] step
-                       14 6 . [3 1 2 3] [PE1.1] step
-             14 6 [3 1 2 3] . [PE1.1] step
-     14 6 [3 1 2 3] [PE1.1] . step
-             14 6 3 [PE1.1] . i [1 2 3] [PE1.1] step
-                     14 6 3 . PE1.1 [1 2 3] [PE1.1] step
-                     14 6 3 . + [+] dupdip [1 2 3] [PE1.1] step
-                       14 9 . [+] dupdip [1 2 3] [PE1.1] step
-                   14 9 [+] . dupdip [1 2 3] [PE1.1] step
-                       14 9 . + 9 [1 2 3] [PE1.1] step
-                         23 . 9 [1 2 3] [PE1.1] step
-                       23 9 . [1 2 3] [PE1.1] step
-               23 9 [1 2 3] . [PE1.1] step
-       23 9 [1 2 3] [PE1.1] . step
-             23 9 1 [PE1.1] . i [2 3] [PE1.1] step
-                     23 9 1 . PE1.1 [2 3] [PE1.1] step
-                     23 9 1 . + [+] dupdip [2 3] [PE1.1] step
-                      23 10 . [+] dupdip [2 3] [PE1.1] step
-                  23 10 [+] . dupdip [2 3] [PE1.1] step
-                      23 10 . + 10 [2 3] [PE1.1] step
-                         33 . 10 [2 3] [PE1.1] step
-                      33 10 . [2 3] [PE1.1] step
-                33 10 [2 3] . [PE1.1] step
-        33 10 [2 3] [PE1.1] . step
-            33 10 2 [PE1.1] . i [3] [PE1.1] step
-                    33 10 2 . PE1.1 [3] [PE1.1] step
-                    33 10 2 . + [+] dupdip [3] [PE1.1] step
-                      33 12 . [+] dupdip [3] [PE1.1] step
-                  33 12 [+] . dupdip [3] [PE1.1] step
-                      33 12 . + 12 [3] [PE1.1] step
-                         45 . 12 [3] [PE1.1] step
-                      45 12 . [3] [PE1.1] step
-                  45 12 [3] . [PE1.1] step
-          45 12 [3] [PE1.1] . step
-            45 12 3 [PE1.1] . i
-                    45 12 3 . PE1.1
-                    45 12 3 . + [+] dupdip
-                      45 15 . [+] dupdip
-                  45 15 [+] . dupdip
-                      45 15 . + 15
-                         60 . 15
-                      60 15 .
-
-
-

So one step through all seven terms brings the counter to 15 and the -total to 60.

-
-
-

How many multiples to sum?

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

We only want the terms less than 1000.

-
999 - 990
-
-
-
9
-
-
-

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')
-
-
-
J('PE1')
-
-
-
233168
-
-
-
-
-

Packing the terms into an integer

-

This form uses no extra storage and produces no unused summands. It’s -good but there’s one more trick we can apply. The list of seven terms -takes up at least seven bytes. But notice that all of the terms are less -than four, and so each can fit in just two bits. We could store all -seven terms in just fourteen bits and use masking and shifts to pick out -each term as we go. This will use less space and save time loading whole -integer terms from the list.

-
    3  2  1  3  1  2  3
-0b 11 10 01 11 01 10 11 == 14811
-
-
-
0b11100111011011
-
-
-
14811
-
-
-
define('PE1.2 == [3 & PE1.1] dupdip 2 >>')
-
-
-
V('0 0 14811 PE1.2')
-
-
-
                      . 0 0 14811 PE1.2
-                    0 . 0 14811 PE1.2
-                  0 0 . 14811 PE1.2
-            0 0 14811 . PE1.2
-            0 0 14811 . [3 & PE1.1] dupdip 2 >>
-0 0 14811 [3 & PE1.1] . dupdip 2 >>
-            0 0 14811 . 3 & PE1.1 14811 2 >>
-          0 0 14811 3 . & PE1.1 14811 2 >>
-                0 0 3 . PE1.1 14811 2 >>
-                0 0 3 . + [+] dupdip 14811 2 >>
-                  0 3 . [+] dupdip 14811 2 >>
-              0 3 [+] . dupdip 14811 2 >>
-                  0 3 . + 3 14811 2 >>
-                    3 . 3 14811 2 >>
-                  3 3 . 14811 2 >>
-            3 3 14811 . 2 >>
-          3 3 14811 2 . >>
-             3 3 3702 .
-
-
-
V('3 3 3702 PE1.2')
-
-
-
                     . 3 3 3702 PE1.2
-                   3 . 3 3702 PE1.2
-                 3 3 . 3702 PE1.2
-            3 3 3702 . PE1.2
-            3 3 3702 . [3 & PE1.1] dupdip 2 >>
-3 3 3702 [3 & PE1.1] . dupdip 2 >>
-            3 3 3702 . 3 & PE1.1 3702 2 >>
-          3 3 3702 3 . & PE1.1 3702 2 >>
-               3 3 2 . PE1.1 3702 2 >>
-               3 3 2 . + [+] dupdip 3702 2 >>
-                 3 5 . [+] dupdip 3702 2 >>
-             3 5 [+] . dupdip 3702 2 >>
-                 3 5 . + 5 3702 2 >>
-                   8 . 5 3702 2 >>
-                 8 5 . 3702 2 >>
-            8 5 3702 . 2 >>
-          8 5 3702 2 . >>
-             8 5 925 .
-
-
-
V('0 0 14811 7 [PE1.2] times pop')
-
-
-
                      . 0 0 14811 7 [PE1.2] times pop
-                    0 . 0 14811 7 [PE1.2] times pop
-                  0 0 . 14811 7 [PE1.2] times pop
-            0 0 14811 . 7 [PE1.2] times pop
-          0 0 14811 7 . [PE1.2] times pop
-  0 0 14811 7 [PE1.2] . times pop
-    0 0 14811 [PE1.2] . i 6 [PE1.2] times pop
-            0 0 14811 . PE1.2 6 [PE1.2] times pop
-            0 0 14811 . [3 & PE1.1] dupdip 2 >> 6 [PE1.2] times pop
-0 0 14811 [3 & PE1.1] . dupdip 2 >> 6 [PE1.2] times pop
-            0 0 14811 . 3 & PE1.1 14811 2 >> 6 [PE1.2] times pop
-          0 0 14811 3 . & PE1.1 14811 2 >> 6 [PE1.2] times pop
-                0 0 3 . PE1.1 14811 2 >> 6 [PE1.2] times pop
-                0 0 3 . + [+] dupdip 14811 2 >> 6 [PE1.2] times pop
-                  0 3 . [+] dupdip 14811 2 >> 6 [PE1.2] times pop
-              0 3 [+] . dupdip 14811 2 >> 6 [PE1.2] times pop
-                  0 3 . + 3 14811 2 >> 6 [PE1.2] times pop
-                    3 . 3 14811 2 >> 6 [PE1.2] times pop
-                  3 3 . 14811 2 >> 6 [PE1.2] times pop
-            3 3 14811 . 2 >> 6 [PE1.2] times pop
-          3 3 14811 2 . >> 6 [PE1.2] times pop
-             3 3 3702 . 6 [PE1.2] times pop
-           3 3 3702 6 . [PE1.2] times pop
-   3 3 3702 6 [PE1.2] . times pop
-     3 3 3702 [PE1.2] . i 5 [PE1.2] times pop
-             3 3 3702 . PE1.2 5 [PE1.2] times pop
-             3 3 3702 . [3 & PE1.1] dupdip 2 >> 5 [PE1.2] times pop
- 3 3 3702 [3 & PE1.1] . dupdip 2 >> 5 [PE1.2] times pop
-             3 3 3702 . 3 & PE1.1 3702 2 >> 5 [PE1.2] times pop
-           3 3 3702 3 . & PE1.1 3702 2 >> 5 [PE1.2] times pop
-                3 3 2 . PE1.1 3702 2 >> 5 [PE1.2] times pop
-                3 3 2 . + [+] dupdip 3702 2 >> 5 [PE1.2] times pop
-                  3 5 . [+] dupdip 3702 2 >> 5 [PE1.2] times pop
-              3 5 [+] . dupdip 3702 2 >> 5 [PE1.2] times pop
-                  3 5 . + 5 3702 2 >> 5 [PE1.2] times pop
-                    8 . 5 3702 2 >> 5 [PE1.2] times pop
-                  8 5 . 3702 2 >> 5 [PE1.2] times pop
-             8 5 3702 . 2 >> 5 [PE1.2] times pop
-           8 5 3702 2 . >> 5 [PE1.2] times pop
-              8 5 925 . 5 [PE1.2] times pop
-            8 5 925 5 . [PE1.2] times pop
-    8 5 925 5 [PE1.2] . times pop
-      8 5 925 [PE1.2] . i 4 [PE1.2] times pop
-              8 5 925 . PE1.2 4 [PE1.2] times pop
-              8 5 925 . [3 & PE1.1] dupdip 2 >> 4 [PE1.2] times pop
-  8 5 925 [3 & PE1.1] . dupdip 2 >> 4 [PE1.2] times pop
-              8 5 925 . 3 & PE1.1 925 2 >> 4 [PE1.2] times pop
-            8 5 925 3 . & PE1.1 925 2 >> 4 [PE1.2] times pop
-                8 5 1 . PE1.1 925 2 >> 4 [PE1.2] times pop
-                8 5 1 . + [+] dupdip 925 2 >> 4 [PE1.2] times pop
-                  8 6 . [+] dupdip 925 2 >> 4 [PE1.2] times pop
-              8 6 [+] . dupdip 925 2 >> 4 [PE1.2] times pop
-                  8 6 . + 6 925 2 >> 4 [PE1.2] times pop
-                   14 . 6 925 2 >> 4 [PE1.2] times pop
-                 14 6 . 925 2 >> 4 [PE1.2] times pop
-             14 6 925 . 2 >> 4 [PE1.2] times pop
-           14 6 925 2 . >> 4 [PE1.2] times pop
-             14 6 231 . 4 [PE1.2] times pop
-           14 6 231 4 . [PE1.2] times pop
-   14 6 231 4 [PE1.2] . times pop
-     14 6 231 [PE1.2] . i 3 [PE1.2] times pop
-             14 6 231 . PE1.2 3 [PE1.2] times pop
-             14 6 231 . [3 & PE1.1] dupdip 2 >> 3 [PE1.2] times pop
- 14 6 231 [3 & PE1.1] . dupdip 2 >> 3 [PE1.2] times pop
-             14 6 231 . 3 & PE1.1 231 2 >> 3 [PE1.2] times pop
-           14 6 231 3 . & PE1.1 231 2 >> 3 [PE1.2] times pop
-               14 6 3 . PE1.1 231 2 >> 3 [PE1.2] times pop
-               14 6 3 . + [+] dupdip 231 2 >> 3 [PE1.2] times pop
-                 14 9 . [+] dupdip 231 2 >> 3 [PE1.2] times pop
-             14 9 [+] . dupdip 231 2 >> 3 [PE1.2] times pop
-                 14 9 . + 9 231 2 >> 3 [PE1.2] times pop
-                   23 . 9 231 2 >> 3 [PE1.2] times pop
-                 23 9 . 231 2 >> 3 [PE1.2] times pop
-             23 9 231 . 2 >> 3 [PE1.2] times pop
-           23 9 231 2 . >> 3 [PE1.2] times pop
-              23 9 57 . 3 [PE1.2] times pop
-            23 9 57 3 . [PE1.2] times pop
-    23 9 57 3 [PE1.2] . times pop
-      23 9 57 [PE1.2] . i 2 [PE1.2] times pop
-              23 9 57 . PE1.2 2 [PE1.2] times pop
-              23 9 57 . [3 & PE1.1] dupdip 2 >> 2 [PE1.2] times pop
-  23 9 57 [3 & PE1.1] . dupdip 2 >> 2 [PE1.2] times pop
-              23 9 57 . 3 & PE1.1 57 2 >> 2 [PE1.2] times pop
-            23 9 57 3 . & PE1.1 57 2 >> 2 [PE1.2] times pop
-               23 9 1 . PE1.1 57 2 >> 2 [PE1.2] times pop
-               23 9 1 . + [+] dupdip 57 2 >> 2 [PE1.2] times pop
-                23 10 . [+] dupdip 57 2 >> 2 [PE1.2] times pop
-            23 10 [+] . dupdip 57 2 >> 2 [PE1.2] times pop
-                23 10 . + 10 57 2 >> 2 [PE1.2] times pop
-                   33 . 10 57 2 >> 2 [PE1.2] times pop
-                33 10 . 57 2 >> 2 [PE1.2] times pop
-             33 10 57 . 2 >> 2 [PE1.2] times pop
-           33 10 57 2 . >> 2 [PE1.2] times pop
-             33 10 14 . 2 [PE1.2] times pop
-           33 10 14 2 . [PE1.2] times pop
-   33 10 14 2 [PE1.2] . times pop
-     33 10 14 [PE1.2] . i 1 [PE1.2] times pop
-             33 10 14 . PE1.2 1 [PE1.2] times pop
-             33 10 14 . [3 & PE1.1] dupdip 2 >> 1 [PE1.2] times pop
- 33 10 14 [3 & PE1.1] . dupdip 2 >> 1 [PE1.2] times pop
-             33 10 14 . 3 & PE1.1 14 2 >> 1 [PE1.2] times pop
-           33 10 14 3 . & PE1.1 14 2 >> 1 [PE1.2] times pop
-              33 10 2 . PE1.1 14 2 >> 1 [PE1.2] times pop
-              33 10 2 . + [+] dupdip 14 2 >> 1 [PE1.2] times pop
-                33 12 . [+] dupdip 14 2 >> 1 [PE1.2] times pop
-            33 12 [+] . dupdip 14 2 >> 1 [PE1.2] times pop
-                33 12 . + 12 14 2 >> 1 [PE1.2] times pop
-                   45 . 12 14 2 >> 1 [PE1.2] times pop
-                45 12 . 14 2 >> 1 [PE1.2] times pop
-             45 12 14 . 2 >> 1 [PE1.2] times pop
-           45 12 14 2 . >> 1 [PE1.2] times pop
-              45 12 3 . 1 [PE1.2] times pop
-            45 12 3 1 . [PE1.2] times pop
-    45 12 3 1 [PE1.2] . times pop
-      45 12 3 [PE1.2] . i pop
-              45 12 3 . PE1.2 pop
-              45 12 3 . [3 & PE1.1] dupdip 2 >> pop
-  45 12 3 [3 & PE1.1] . dupdip 2 >> pop
-              45 12 3 . 3 & PE1.1 3 2 >> pop
-            45 12 3 3 . & PE1.1 3 2 >> pop
-              45 12 3 . PE1.1 3 2 >> pop
-              45 12 3 . + [+] dupdip 3 2 >> pop
-                45 15 . [+] dupdip 3 2 >> pop
-            45 15 [+] . dupdip 3 2 >> pop
-                45 15 . + 15 3 2 >> pop
-                   60 . 15 3 2 >> pop
-                60 15 . 3 2 >> pop
-              60 15 3 . 2 >> pop
-            60 15 3 2 . >> pop
-              60 15 0 . pop
-                60 15 .
-
-
-

And so we have at last:

-
define('PE1 == 0 0 66 [14811 7 [PE1.2] times pop] times 14811 4 [PE1.2] times popop')
-
-
-
J('PE1')
-
-
-
233168
-
-
-
-
-

Let’s refactor

-
  14811 7 [PE1.2] times pop
-  14811 4 [PE1.2] times pop
-  14811 n [PE1.2] times pop
-n 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')
-
-
-
J('PE1')
-
-
-
233168
-
-
-

Here’s our joy program all in one place. It doesn’t make so much sense, -but if you have read through the above description of how it was derived -I hope it’s clear.

-
PE1.1 == + [+] dupdip
-PE1.2 == [3 & PE1.1] dupdip 2 >>
-PE1.3 == 14811 swap [PE1.2] times pop
-PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop
-
-
-
-
-
-

Generator Version

-

It’s a little clunky iterating sixty-six times though the seven numbers -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]')
-
-
-
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]
-
-
-

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 +')
-
-
-
466
-
-
-
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')
-
-
-
999
-
-
-

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')
-
-
-
233168
-
-
-
-
-

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')
-
-
-
55
-
-
-

Instead of summing them, -observe:

-
  10  9  8  7  6
-+  1  2  3  4  5
----- -- -- -- --
-  11 11 11 11 11
-
-  11 * 5 = 55
-
-
-

From the above example we can deduce that the sum of the first N -positive integers is:

-
(N + 1) * N / 2
-
-
-

(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')
-
-
-
V('10 F')
-
-
-
      . 10 F
-   10 . F
-   10 . dup ++ * 2 floordiv
-10 10 . ++ * 2 floordiv
-10 11 . * 2 floordiv
-  110 . 2 floordiv
-110 2 . floordiv
-   55 .
-
-
-

We can apply the same reasoning to the PE1 problem.

-

Between 0 and 990 inclusive there are sixty-six “blocks” of seven terms -each, starting with:

-
[3 5 6 9 10 12 15]
-
-
-

And ending with:

-
[978 980 981 984 985 987 990]
-
-
-

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')
-
-
-
[[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')
-
-
-
[993 992 991 993 991 992 993]
-
-
-

(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')
-
-
-
6945
-
-
-

Since there are sixty-six blocks and we are pairing them up, there must -be thirty-three pairs, each of which sums to 6945. We also have these -additional unpaired terms between 990 and 1000:

-
993 995 996 999
-
-
-

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')
-
-
-
233168
-
-
-

It’s worth noting, I think, that this same reasoning holds for any two -numbers \(n\) and \(m\) the multiples of which we hope to sum. -The multiples would have a cycle of differences of length \(k\) and -so we could compute the sum of \(Nk\) multiples as above.

-

The sequence of differences will always be a palidrome. Consider an -interval spanning the least common multiple of \(n\) and \(m\):

-
|   |   |   |   |   |   |   |
-|      |      |      |      |
-
-
-

Here we have 4 and 7, and you can read off the sequence of differences -directly from the diagram: 4 3 1 4 2 2 4 1 3 4.

-

Geometrically, the actual values of \(n\) and \(m\) and their -lcm don’t matter, the pattern they make will always be symmetrical -around its midpoint. The same reasoning holds for multiples of more than -two numbers.

-
-
-

The Simplest Program

-

Of course, the simplest joy program for the first Project Euler problem -is just:

-
PE1 == 233168
-
-
-

Fin.

-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html b/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html deleted file mode 100644 index 166daab..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Generator_Programs.html +++ /dev/null @@ -1,584 +0,0 @@ - - - - - - - - - Using x to Generate Values — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Using x to Generate Values

-

Cf. jp-reprod.html

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

Consider the x combinator:

-
x == dup i
-
-
-

We can apply it to a quoted program consisting of some value a and -some function B:

-
[a B] x
-[a B] a B
-
-
-

Let B function swap the a with the quote and run some -function C on it to generate a new value b:

-
B == swap [C] dip
-
-[a B] a B
-[a B] a swap [C] dip
-a [a B]      [C] dip
-a C [a B]
-b [a B]
-
-
-

Now discard the quoted a with rest then cons b:

-
b [a B] rest cons
-b [B]        cons
-[b B]
-
-
-

Altogether, this is the definition of B:

-
B == swap [C] dip rest cons
-
-
-

We can make a generator for the Natural numbers (0, 1, 2, …) by using -0 for a and [dup ++] for [C]:

-
[0 swap [dup ++] dip rest cons]
-
-
-

Let’s try it:

-
V('[0 swap [dup ++] dip rest cons] x')
-
-
-
                                           . [0 swap [dup ++] dip rest cons] x
-           [0 swap [dup ++] dip rest cons] . x
-           [0 swap [dup ++] dip rest cons] . 0 swap [dup ++] dip rest cons
-         [0 swap [dup ++] dip rest cons] 0 . swap [dup ++] dip rest cons
-         0 [0 swap [dup ++] dip rest cons] . [dup ++] dip rest cons
-0 [0 swap [dup ++] dip rest cons] [dup ++] . dip rest cons
-                                         0 . dup ++ [0 swap [dup ++] dip rest cons] rest cons
-                                       0 0 . ++ [0 swap [dup ++] dip rest cons] rest cons
-                                       0 1 . [0 swap [dup ++] dip rest cons] rest cons
-       0 1 [0 swap [dup ++] dip rest cons] . rest cons
-         0 1 [swap [dup ++] dip rest cons] . cons
-         0 [1 swap [dup ++] dip rest cons] .
-
-
-

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')
-
-
-
0 1 2 3 4
-
-
-
-

direco

-
define('direco == dip rest cons')
-
-
-
V('[0 swap [dup ++] direco] x')
-
-
-
                                    . [0 swap [dup ++] direco] x
-           [0 swap [dup ++] direco] . x
-           [0 swap [dup ++] direco] . 0 swap [dup ++] direco
-         [0 swap [dup ++] direco] 0 . swap [dup ++] direco
-         0 [0 swap [dup ++] direco] . [dup ++] direco
-0 [0 swap [dup ++] direco] [dup ++] . direco
-0 [0 swap [dup ++] direco] [dup ++] . dip rest cons
-                                  0 . dup ++ [0 swap [dup ++] direco] rest cons
-                                0 0 . ++ [0 swap [dup ++] direco] rest cons
-                                0 1 . [0 swap [dup ++] direco] rest cons
-       0 1 [0 swap [dup ++] direco] . rest cons
-         0 1 [swap [dup ++] direco] . cons
-         0 [1 swap [dup ++] direco] .
-
-
-
-
-

Making Generators

-

We want to define a function that accepts a and [C] and builds -our quoted program:

-
         a [C] G
--------------------------
-   [a swap [C] direco]
-
-
-

Working in reverse:

-
[a swap   [C] direco] cons
-a [swap   [C] direco] concat
-a [swap] [[C] direco] swap
-a [[C] direco] [swap]
-a [C] [direco] cons [swap]
-
-
-

Reading from the bottom up:

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

Let’s try it out:

-
J('0 [dup ++] G')
-
-
-
[0 swap [dup ++] direco]
-
-
-
J('0 [dup ++] G x x x pop')
-
-
-
0 1 2
-
-
-
-

Powers of 2

-
J('1 [dup 1 <<] G x x x x x x x x x pop')
-
-
-
1 2 4 8 16 32 64 128 256
-
-
-
-
-

[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')
-
-
-
23 24 25 26 27 [28 swap [dup ++] direco]
-
-
-
-
-
-

Generating Multiples of Three and Five

-

Look at the treatment of the Project Euler Problem One in the -“Developing a Program” notebook and you’ll see that we might be -interested in generating an endless cycle of:

-
3 2 1 3 1 2 3
-
-
-

To do this we want to encode the numbers as pairs of bits in a single -int:

-
    3  2  1  3  1  2  3
-0b 11 10 01 11 01 10 11 == 14811
-
-
-

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 >>')
-
-
-
V('14811 PE1.1')
-
-
-
                  . 14811 PE1.1
-            14811 . PE1.1
-            14811 . dup [3 &] dip 2 >>
-      14811 14811 . [3 &] dip 2 >>
-14811 14811 [3 &] . dip 2 >>
-            14811 . 3 & 14811 2 >>
-          14811 3 . & 14811 2 >>
-                3 . 14811 2 >>
-          3 14811 . 2 >>
-        3 14811 2 . >>
-           3 3702 .
-
-
-

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

-
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')
-
-
-
3 2 1 3 1 2 3 [0 swap [PE1.1] direco]
-
-
-
-

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')
-
-
-
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')
-
-
-
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]
-
-
-

(It would be more efficient to reset the int every seven cycles but -that’s a little beyond the scope of this article. This solution does -extra work, but not much, and we’re not using it “in production” as they -say.)

-
-
-

Run 466 times

-

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 +')
-
-
-
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')
-
-
-
3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 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')
-
-
-
999
-
-
-
-
-
-

Project Euler Problem One

-
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')
-
-
-
233168
-
-
-
-
-

A generator for the Fibonacci Sequence.

-

Consider:

-
[b a F] x
-[b a F] b a F
-
-
-

The obvious first thing to do is just add b and a:

-
[b a F] b a +
-[b a F] b+a
-
-
-

From here we want to arrive at:

-
b [b+a b F]
-
-
-

Let’s start with swons:

-
[b a F] b+a swons
-[b+a b a F]
-
-
-

Considering this quote as a stack:

-
F a b b+a
-
-
-

We want to get it to:

-
F b b+a b
-
-
-

So:

-
F a b b+a popdd over
-F b b+a b
-
-
-

And therefore:

-
[b+a b a F] [popdd over] infra
-[b b+a b F]
-
-
-

But we can just use cons to carry b+a into the quote:

-
[b a F] b+a [popdd over] cons infra
-[b a F] [b+a popdd over]      infra
-[b b+a b F]
-
-
-

Lastly:

-
[b b+a b F] uncons
-b [b+a b F]
-
-
-

Putting it all together:

-
F == + [popdd over] cons infra uncons
-fib_gen == [1 1 F]
-
-
-
define('fib == + [popdd over] cons infra uncons')
-
-
-
define('fib_gen == [1 1 fib]')
-
-
-
J('fib_gen 10 [x] times')
-
-
-
1 2 3 5 8 13 21 34 55 89 [144 89 fib]
-
-
-
-
-

Project Euler Problem Two

-
-

By considering the terms in the Fibonacci sequence whose values do -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')
-
-
-

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

-
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')
-
-
-
J('PE2')
-
-
-
4613732
-
-
-

Here’s the collected program definitions:

-
fib == + swons [popdd over] infra uncons
-fib_gen == [1 1 fib]
-
-even == dup 2 %
->4M == 4000000 >
-
-PE2.1 == even [+] [pop] branch
-PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec
-
-
-
-

Even-valued Fibonacci Terms

-

Using o for odd and e for even:

-
o + o = e
-e + e = e
-o + e = o
-
-
-

So the Fibonacci sequence considered in terms of just parity would be:

-
o o e o o e o o e o o e o o e o o e
-1 1 2 3 5 8 . . .
-
-
-

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.
-
-
-
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')
-
-
-
2 [3 2 fib]
-
-
-
define('PE2.2 == x x x [popop] dipd')
-
-
-
J('[1 0 fib] 10 [PE2.2] times')
-
-
-
2 8 34 144 610 2584 10946 46368 196418 832040 [1346269 832040 fib]
-
-
-

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')
-
-
-
4613732
-
-
-
-
-
-

How to compile these?

-

You would probably start with a special version of G, and perhaps -modifications to the default x?

-
-
-

An Interesting Variation

-
define('codireco == cons dip rest cons')
-
-
-
V('[0 [dup ++] codireco] x')
-
-
-
                                 . [0 [dup ++] codireco] x
-           [0 [dup ++] codireco] . x
-           [0 [dup ++] codireco] . 0 [dup ++] codireco
-         [0 [dup ++] codireco] 0 . [dup ++] codireco
-[0 [dup ++] codireco] 0 [dup ++] . codireco
-[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
-[0 [dup ++] codireco] [0 dup ++] . dip rest cons
-                                 . 0 dup ++ [0 [dup ++] codireco] rest cons
-                               0 . dup ++ [0 [dup ++] codireco] rest cons
-                             0 0 . ++ [0 [dup ++] codireco] rest cons
-                             0 1 . [0 [dup ++] codireco] rest cons
-       0 1 [0 [dup ++] codireco] . rest cons
-         0 1 [[dup ++] codireco] . cons
-         0 [1 [dup ++] codireco] .
-
-
-
define('G == [codireco] cons cons')
-
-
-
J('230 [dup ++] G 5 [x] times pop')
-
-
-
230 231 232 233 234
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Intro.html b/docs/sphinx_docs/_build/html/notebooks/Intro.html deleted file mode 100644 index d56d9e0..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Intro.html +++ /dev/null @@ -1,376 +0,0 @@ - - - - - - - - - Thun: Joy in Python — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Thun: Joy in Python

-

This implementation is meant as a tool for exploring the programming -model and method of Joy. Python seems like a great implementation -language for Joy for several reasons.

-
    -
  • We can lean on the Python immutable types for our basic semantics and types: ints, floats, strings, and tuples, which enforces functional purity.

  • -
  • We get garbage collection for free.

  • -
  • Compilation via Cython.

  • -
  • Python is a “glue language” with loads of libraries which we can wrap in Joy functions.

  • -
-
-

Read-Eval-Print Loop (REPL)

-

The main way to interact with the Joy interpreter is through a simple -REPL -that you start by running the package:

-
$ python3 -m joy
-Thun - Copyright © 2017 Simon Forman
-This program comes with ABSOLUTELY NO WARRANTY; for details type "warranty".
-This is free software, and you are welcome to redistribute it
-under certain conditions; type "sharing" for details.
-Type "words" to see a list of all words, and "[<name>] help" to print the
-docs for a word.
-
-
-<-top
-
-joy? _
-
-
-

The <-top marker points to the top of the (initially empty) stack. -You can enter Joy notation at the prompt and a trace of evaluation will -be printed followed by the stack and prompt again:

-
joy? 23 sqr 18 +
-
-547 <-top
-
-joy?
-
-
-

There is a trace combinator:

-
joy? 23 [sqr 18 +] trace
-    23 . sqr 18 +
-    23 . dup mul 18 +
- 23 23 . mul 18 +
-   529 . 18 +
-529 18 . +
-   547 .
-
-547 <-top
-
-joy?
-
-
-
-
-

The Stack

-

In Joy, in addition to the types Boolean, integer, float, and string, -there is a single sequence type represented by enclosing a sequence of -terms in brackets [...]. This sequence type is used to represent -both the stack and the expression. It is a cons -list made from Python -tuples.

-
-
-

Purely Functional Datastructures

-

Because Joy stacks are made out of Python tuples they are immutable, as are the other Python types we “borrow” for Joy, so all Joy datastructures are purely functional.

-
-
-

The joy() function

-
-

An Interpreter

-

The joy() interpreter function is extrememly simple. It accepts a stack, an -expression, and a dictionary, and it iterates through the expression -putting values onto the stack and delegating execution to functions which it -looks up in the dictionary.

-
-
-

Continuation-Passing Style

-

One day I thought, What happens if you rewrite Joy to use -CPS? I -made all the functions accept and return the expression as well as the -stack and found that all the combinators could be rewritten to work by -modifying the expression rather than making recursive calls to the -joy() function.

-
-
-

View function

-

The joy() function accepts an optional viewer argument that -is a function which it calls on -each iteration passing the current stack and expression just before -evaluation. This can be used for tracing, breakpoints, retrying after -exceptions, or interrupting an evaluation and saving to disk or sending -over the network to resume later. The stack and expression together -contain all the state of the computation at each step.

-
-
-

The TracePrinter.

-

A viewer records each step of the evaluation of a Joy program. The -TracePrinter has a facility for printing out a trace of the -evaluation, one line per step. Each step is aligned to the current -interpreter position, signified by a period separating the stack on the -left from the pending expression (“continuation”) on the right.

-
-
-
-

Parser

-

The parser is extremely simple. The undocumented re.Scanner class -does the tokenizing and then the parser builds the tuple -structure out of the tokens. There’s no Abstract Syntax Tree or anything -like that.

-
-

Symbols

-

TODO: Symbols are just a string subclass; used by the parser to represent function names and by the interpreter to look up functions in the dictionary. N.B.: Symbols are not looked up at parse-time. You could define recursive functions, er, recusively, without genrec or other recursion combinators foo == ... foo ... but don’t do that.

-
-
-

Token Regular Expressions

-
123   1.2   'single quotes'  "double quotes"   function
-
-
-

TBD (look in the :module: joy.parser module.)

-
-
-

Examples

-
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
-
-
-
((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.
-
-
-
(1, (23, (('four', ((-5.0, ()), (cons, ()))), (8888, ()))))
-
-
-
joy.parser.text_to_expression('[][][][][]')  # Five empty lists.
-
-
-
((), ((), ((), ((), ((), ())))))
-
-
-
joy.parser.text_to_expression('[[[[[]]]]]')  # Five nested lists.
-
-
-
((((((), ()), ()), ()), ()), ())
-
-
-
-
-
-

Library

-

The Joy library of functions (aka commands, or “words” after Forth -usage) encapsulates all the actual functionality (no pun intended) of -the Joy system. There are simple functions such as addition add (or -+, 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)
-
-
-
def dip(stack, expression, dictionary):
-  (quote, (x, stack)) = stack
-  expression = x, expression
-  return stack, concat(quote, expression), dictionary
-
-
-

Some functions are defined in equations in terms of other functions. -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
-
-
-
second == rest first
-third == rest rest first
-product == 1 swap [*] step
-swons == swap cons
-swoncat == swap concat
-flatten == [] swap [concat] step
-unit == [] cons
-quoted == [unit] dip
-unquoted == [i] dip
-enstacken == stack [clear] dip
-disenstacken == ? [uncons ?] loop pop
-? == dup truthy
-dinfrirst == dip infra first
-nullary == [stack] dinfrirst
-unary == [stack [pop] dip] dinfrirst
-binary == [stack [popop] dip] dinfrirst
-ternary == [stack [popop pop] dip] dinfrirst
-pam == [i] map
-run == [] swap infra
-sqr == dup mul
-size == 0 swap [pop ++] step
-cleave == [i] app2 [popd] dip
-average == [sum 1.0 ] [size] cleave /
-gcd == 1 [tuck modulus dup 0 >] loop pop
-least_fraction == dup [gcd] infra [div] concat map
-*fraction == [uncons] dip uncons [swap] dip concat [] infra [*] dip cons
-fraction0 == concat [[swap] dip * [] dip] infra
-down_to_zero == [0 >] [dup --] while
-range_to_zero == unit [down_to_zero] infra
-anamorphism == [pop []] swap [dip swons] genrec
-range == [0 <=] [1 - dup] anamorphism
-while == swap [nullary] cons dup dipd concat loop
-dudipd == dup dipd
-primrec == [i] genrec
-

Currently, there’s no function to add new definitions to the dictionary -from “within” Joy code itself. Adding new definitions remains a -meta-interpreter action. You have to do it yourself, in Python, and wash -your hands afterward.

-

It would be simple enough to define one, but it would open the door to -name binding and break the idea that all state is captured in the -stack and expression. There’s an implicit standard dictionary that -defines the actual semantics of the syntactic stack and expression -datastructures (which only contain symbols, not the actual functions. -Pickle some and see for yourself.)

-
-

“There should be only one.”

-

Which brings me to talking about one of my hopes and dreams for this -notation: “There should be only one.” What I mean is that there should -be one universal standard dictionary of commands, and all bespoke work -done in a UI for purposes takes place by direct interaction and macros. -There would be a Grand Refactoring biannually (two years, not six -months, that’s semi-annually) where any new definitions factored out of -the usage and macros of the previous time, along with new algorithms and -such, were entered into the dictionary and posted to e.g. IPFS.

-

Code should not burgeon wildly, as it does today. The variety of code -should map more-or-less to the well-factored variety of human -computably-solvable problems. There shouldn’t be dozens of chat apps, JS -frameworks, programming languages. It’s a waste of time, a fractal -“thundering herd” -attack on -human mentality.

-
-
-

Literary Code Library

-

If you read over the other notebooks you’ll see that developing code in -Joy is a lot like doing simple mathematics, and the descriptions of the -code resemble math papers. The code also works the first time, no bugs. -If you have any experience programming at all, you are probably -skeptical, as I was, but it seems to work: deriving code mathematically -seems to lead to fewer errors.

-

But my point now is that this great ratio of textual explanation to wind -up with code that consists of a few equations and could fit on an index -card is highly desirable. Less code has fewer errors. The structure of -Joy engenders a kind of thinking that seems to be very effective for -developing structured processes.

-

There seems to be an elegance and power to the notation.

-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Newton-Raphson.html b/docs/sphinx_docs/_build/html/notebooks/Newton-Raphson.html deleted file mode 100644 index 5d23612..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Newton-Raphson.html +++ /dev/null @@ -1,323 +0,0 @@ - - - - - - - - - Newton’s method — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Newton’s method

-

Let’s use the Newton-Raphson method for finding the root of an equation -to write a function that can compute the square root of a number.

-

Cf. “Why Functional Programming Matters” by John -Hughes

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

A Generator for Approximations

-

To make a generator that generates successive approximations let’s start -by assuming an initial approximation and then derive the function that -computes the next approximation:

-
   a F
----------
-    a'
-
-
-
-

A Function to Compute the Next Approximation

-

This is the equation for computing the next approximate value of the -square root:

-

\(a_{i+1} = \frac{(a_i+\frac{n}{a_i})}{2}\)

-
a n over / + 2 /
-a n a    / + 2 /
-a n/a      + 2 /
-a+n/a        2 /
-(a+n/a)/2
-
-
-

The function we want has the argument n in it:

-
F == n over / + 2 /
-
-
-
-
-

Make it into a Generator

-

Our generator would be created by:

-
a [dup F] make_generator
-
-
-

With n as part of the function F, but n is the input to the sqrt -function we’re writing. If we let 1 be the initial approximation:

-
1 n 1 / + 2 /
-1 n/1   + 2 /
-1 n     + 2 /
-n+1       2 /
-(n+1)/2
-
-
-

The generator can be written as:

-
23 1 swap  [over / + 2 /] cons [dup] swoncat make_generator
-1 23       [over / + 2 /] cons [dup] swoncat make_generator
-1       [23 over / + 2 /]      [dup] swoncat make_generator
-1   [dup 23 over / + 2 /]                    make_generator
-
-
-
define('gsra 1 swap [over / + 2 /] cons [dup] swoncat make_generator')
-
-
-
J('23 gsra')
-
-
-
[1 [dup 23 over / + 2 /] codireco]
-
-
-

Let’s drive the generator a few time (with the x combinator) and -square the approximation to see how well it works…

-
J('23 gsra 6 [x popd] times first sqr')
-
-
-
23.0000000001585
-
-
-
-
-
-

Finding Consecutive Approximations within a Tolerance

-

From “Why Functional Programming Matters” by John -Hughes:

-
-

The remainder of a square root finder is a function within, which -takes a tolerance and a list of approximations and looks down the -list for two successive approximations that differ by no more than -the given tolerance.

-
-

(And note that by “list” he means a lazily-evaluated list.)

-

Using the output [a G] of the above generator for square root -approximations, and further assuming that the first term a has been -generated already and epsilon ε is handy on the stack…

-
   a [b G] ε within
----------------------- a b - abs ε <=
-      b
-
-
-   a [b G] ε within
----------------------- a b - abs ε >
-   b [c G] ε within
-
-
-
-

Predicate

-
a [b G]             ε [first - abs] dip <=
-a [b G] first - abs ε                   <=
-a b           - abs ε                   <=
-a-b             abs ε                   <=
-abs(a-b)            ε                   <=
-(abs(a-b)<=ε)
-
-
-
define('_within_P [first - abs] dip <=')
-
-
-
-
-

Base-Case

-
a [b G] ε roll< popop first
-  [b G] ε a     popop first
-  [b G]               first
-   b
-
-
-
define('_within_B roll< popop first')
-
-
-
-
-

Recur

-
a [b G] ε R0 [within] R1
-
-
-
    -
  1. Discard a.

  2. -
  3. Use x combinator to generate next term from G.

  4. -
  5. Run within with i (it is a “tail-recursive” function.)

  6. -
-

Pretty straightforward:

-
a [b G]        ε R0           [within] R1
-a [b G]        ε [popd x] dip [within] i
-a [b G] popd x ε              [within] i
-  [b G]      x ε              [within] i
-b [c G]        ε              [within] i
-b [c G]        ε               within
-
-b [c G] ε within
-
-
-
define('_within_R [popd x] dip')
-
-
-
-
-

Setting up

-

The recursive function we have defined so far needs a slight preamble: -x to prime the generator and the epsilon value to use:

-
[a G] x ε ...
-a [b G] ε ...
-
-
-
define('within x 0.000000001 [_within_P] [_within_B] [_within_R] tailrec')
-define('sqrt gsra within')
-
-
-

Try it out…

-
J('36 sqrt')
-
-
-
6.0
-
-
-
J('23 sqrt')
-
-
-
4.795831523312719
-
-
-

Check it.

-
4.795831523312719**2
-
-
-
22.999999999999996
-
-
-
from math import sqrt
-
-sqrt(23)
-
-
-
4.795831523312719
-
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/NoUpdates.html b/docs/sphinx_docs/_build/html/notebooks/NoUpdates.html deleted file mode 100644 index 797a302..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/NoUpdates.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - No Updates — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

No Updates

-

DRAFT

-
    -
  1. Joy doesn’t need to change.

  2. -
-
-
    -
  1. The interpreter doesn’t need to change, viewer function can customize mainloop. Or use a sub-interpreter (Joy in Joy.) The base interpreter remains static.

  2. -
  3. Once a function has been named and defined never change that name. It’s just not allowed. If you need to change a function foo you have to call it foo_II or something. Once a function (name mapped to behavior) is released to the public that’s it, it’s done.

  4. -
  5. The language evolves by adding new definitions and refactoring, always choosing new names for new functions.

  6. -
-
-
    -
  1. Following Semantic Versioning there will never be a version 2.0.

  2. -
-
-
    -
  1. Major version must be incremented if any backwards incompatible changes are introduced to the public API.

  2. -
  3. We never implement any backwards incompatible changes, so…

  4. -
  5. We could see e.g. Thun version 1.273.3!

  6. -
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Ordered_Binary_Trees.html b/docs/sphinx_docs/_build/html/notebooks/Ordered_Binary_Trees.html deleted file mode 100644 index 6d63e16..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Ordered_Binary_Trees.html +++ /dev/null @@ -1,1380 +0,0 @@ - - - - - - - - - Treating Trees I: Ordered Binary Trees — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Treating Trees I: Ordered Binary Trees

-

Although any expression in Joy can be considered to describe a -tree with the quotes -as compound nodes and the non-quote values as leaf nodes, in this page I -want to talk about ordered binary -trees and how to -make and use them.

-

The basic structure, in a crude type -notation, is:

-
Tree :: [] | [key value Tree Tree]
-
-
-

That says that a Tree is either the empty quote [] or a quote with -four items: a key, a value, and two Trees representing the left and -right branches of the tree.

-

We’re going to derive some recursive functions to work with such -datastructures:

-
Tree-add
-Tree-delete
-Tree-get
-Tree-iter
-Tree-iter-order
-
-
-

Once these functions are defined we have a new “type” to work with, and -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
-
-
-
-

Adding Nodes to the Tree

-

Let’s consider adding nodes to a Tree structure.

-
   Tree value key Tree-add
------------------------------
-            Tree′
-
-
-
-

Adding to an empty node.

-

If the current node is [] then you just return -[key value [] []]:

-
Tree-add == [popop not] [[pop] dipd Tree-new] [R0] [R1] genrec
-
-
-
-

Tree-new

-

Where Tree-new is defined as:

-
   value key Tree-new
-------------------------
-   [key value [] []]
-
-
-

Example:

-
value key swap [[] []] cons cons
-key value      [[] []] cons cons
-key      [value [] []]      cons
-     [key value [] []]
-
-
-

Definition:

-
Tree-new == swap [[] []] cons cons
-
-
-
define('Tree-new == swap [[] []] cons cons')
-
-
-
J('"v" "k" Tree-new')
-
-
-
['k' 'v' [] []]
-
-
-

(As an implementation detail, the [[] []] literal used in the -definition of Tree-new will be reused to supply the constant tail -for all new nodes produced by it. This is one of those cases where you -get amortized storage “for free” by using persistent -datastructures. -Because the tail, which is ((), ((), ())) in Python, is immutable -and embedded in the definition body for Tree-new, all new nodes can -reuse it as their own tail without fear that some other code somewhere -will change it.)

-
-
-
-

Adding to a non-empty node.

-

We now have to derive R0 and R1, consider:

-
[key_n value_n left right] value key R0 [Tree-add] R1
-
-
-

In this case, there are three possibilites: the key can be greater or -less than or equal to the node’s key. In two of those cases we will need -to apply a copy of Tree-add, so R0 is pretty much out of the -picture.

-
[R0] == []
-
-
-
-

A predicate to compare keys.

-
[key_n value_n left right] value key [BTree-add] R1
-
-
-

The first thing we need to do is compare the the key we’re adding to the -node key and branch accordingly:

-
[key_n value_n left right] value key [BTree-add] [P] [T] [E] ifte
-
-
-

That would suggest something like:

-
[key_n value_n left right] value key [BTree-add] P
-[key_n value_n left right] value key [BTree-add] pop roll> pop first >
-[key_n value_n left right] value key                 roll> pop first >
-key [key_n value_n left right] value                 roll> pop first >
-key key_n                                                            >
-Boolean
-
-
-

Let’s abstract the predicate just a little to let us specify the -comparison operator:

-
P > == pop roll> pop first >
-P < == pop roll> pop first <
-P   == pop roll> pop first
-
-
-
define('P == pop roll> pop first')
-
-
-
J('["old_key" 23 [] []] 17 "new_key" ["..."] P')
-
-
-
'new_key' 'old_key'
-
-
-
-
-

If the key we’re adding is greater than the node’s key.

-

Here the parentheses are meant to signify that the expression is not -literal, the code in the parentheses is meant to have been evaluated:

-
   [key_n value_n left right] value key [Tree-add] T
--------------------------------------------------------
-   [key_n value_n left (Tree-add key value right)]
-
-
-

So how do we do this? We’re going to want to use infra on some -function K that has the key and value to work with, as well as the -quoted copy of Tree-add to apply somehow. Considering the node as a -stack:

-
   right left value_n key_n value key [Tree-add] K
------------------------------------------------------
-   right value key Tree-add left value_n key_n
-
-
-

Pretty easy:

-
right left value_n key_n value key [Tree-add] cons cons dipdd
-right left value_n key_n [value key Tree-add]           dipdd
-right value key Tree-add left value_n key_n
-
-
-

So:

-
K == cons cons dipdd
-
-
-

Looking at it from the point-of-view of the node as node again:

-
[key_n value_n left right] [value key [Tree-add] K] infra
-
-
-

Expand K and evaluate a little:

-
[key_n value_n left right] [value key [Tree-add] K] infra
-[key_n value_n left right] [value key [Tree-add] cons cons dipdd] infra
-[key_n value_n left right] [[value key Tree-add]           dipdd] infra
-
-
-

Then, working backwards:

-
[key_n value_n left right] [[value key Tree-add]           dipdd]      infra
-[key_n value_n left right] [value key Tree-add]           [dipdd] cons infra
-[key_n value_n left right] value key [Tree-add] cons cons [dipdd] cons infra
-
-
-

And so T is just:

-
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')
-
-
-
['old_k' 'old_value' 'left' 'Tree-add' 'new_key' 'new_value' 'right']
-
-
-
-
-

If the key we’re adding is less than the node’s key.

-

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
-
-
-
define('E == [P <] [Te] [Ee] ifte')
-
-
-

In this case Te works that same as T but on the left child tree -instead of the right, so the only difference is that it must use -dipd instead of dipdd:

-
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')
-
-
-
['old_k' 'old_value' 'Tree-add' 'new_key' 'new_value' 'left' 'right']
-
-
-
-
-

Else the keys must be equal.

-

This means we must find:

-
   [key old_value left right] new_value key [Tree-add] Ee
-------------------------------------------------------------
-   [key new_value left right]
-
-
-

This is another easy one:

-
Ee == pop swap roll< rest rest cons cons
-
-
-

Example:

-
[key old_value left right] new_value key [Tree-add] pop swap roll< rest rest cons cons
-[key old_value left right] new_value key                swap roll< rest rest cons cons
-[key old_value left right] key new_value                     roll< rest rest cons cons
-key new_value [key old_value left right]                           rest rest cons cons
-key new_value [              left right]                                     cons cons
-              [key new_value left right]
-
-
-
define('Ee == pop swap roll< rest rest cons cons')
-
-
-
J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee')
-
-
-
['k' 'new_value' 'left' 'right']
-
-
-
-
-
-

Now we can define Tree-add

-
Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec
-
-
-

Putting it all together:

-
Tree-new == swap [[] []] cons cons
-P == pop roll> pop first
-T == cons cons [dipdd] cons infra
-Te == cons cons [dipd] cons infra
-Ee == pop swap roll< rest rest cons cons
-E == [P <] [Te] [Ee] ifte
-R == [P >] [T] [E] ifte
-
-Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec
-
-
-
define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec')
-
-
-
-
-

Examples

-
J('[] 23 "b" Tree-add')  # Initial
-
-
-
['b' 23 [] []]
-
-
-
J('["b" 23 [] []] 88 "c" Tree-add')  # Greater than
-
-
-
['b' 23 [] ['c' 88 [] []]]
-
-
-
J('["b" 23 [] []] 88 "a" Tree-add')  # Less than
-
-
-
['b' 23 ['a' 88 [] []] []]
-
-
-
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.
-
-
-
['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
-
-
-
J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step')
-
-
-
['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
-
-
-
-
-
-

Interlude: cmp combinator

-

Instead of mucking about with nested ifte combinators let’s use -cmp which takes two values and three quoted programs on the stack -and runs one of the three depending on the results of comparing the two -values:

-
   a b [G] [E] [L] cmp
-------------------------- a > b
-        G
-
-   a b [G] [E] [L] cmp
-------------------------- a = b
-            E
-
-   a b [G] [E] [L] cmp
-------------------------- a < b
-                L
-
-
-
J("1 0 ['G'] ['E'] ['L'] cmp")
-
-
-
'G'
-
-
-
J("1 1 ['G'] ['E'] ['L'] cmp")
-
-
-
'E'
-
-
-
J("0 1 ['G'] ['E'] ['L'] cmp")
-
-
-
'L'
-
-
-
-

Redefine Tree-add

-

We need a new non-destructive predicate P:

-
   [node_key node_value left right] value key [Tree-add] P
-------------------------------------------------------------------------
-   [node_key node_value left right] value key [Tree-add] key node_key
-
-
-

Let’s start with over to get a copy of the key and then apply some -function Q with the nullary combinator so it can dig out the -node key (by throwing everything else away):

-
P == over [Q] nullary
-
-[node_key node_value left right] value key [Tree-add] over [Q] nullary
-[node_key node_value left right] value key [Tree-add] key  [Q] nullary
-
-
-

And Q would be:

-
Q == popop popop first
-
-[node_key node_value left right] value key [Tree-add] key Q
-[node_key node_value left right] value key [Tree-add] key popop popop first
-[node_key node_value left right] value key                      popop first
-[node_key node_value left right]                                      first
- node_key
-
-
-

Or just:

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

Using cmp to simplify our code above at -``R1` <#Adding-to-a-non-empty-node.>`__:

-
[node_key node_value left right] value key [Tree-add] R1
-[node_key node_value left right] value key [Tree-add] P [T] [E] [Te] cmp
-
-
-

The line above becomes one of the three lines below:

-
[node_key node_value left right] value key [Tree-add] T
-[node_key node_value left right] value key [Tree-add] E
-[node_key node_value left right] value key [Tree-add] Te
-
-
-

The definition is a little longer but, I think, more elegant and easier -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')
-
-
-
J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add')  # Still works.
-
-
-
['b' 23 ['a' 88 [] []] ['c' 44 [] []]]
-
-
-
-
-
-

A Function to Traverse this Structure

-

Let’s take a crack at writing a function that can recursively iterate or -traverse these trees.

-
-

Base case []

-

The stopping predicate just has to detect the empty list:

-
Tree-iter == [not] [E] [R0] [R1] genrec
-
-
-

And since there’s nothing at this node, we just pop it:

-
Tree-iter == [not] [pop] [R0] [R1] genrec
-
-
-
-
-

Node case [key value left right]

-

Now we need to figure out R0 and R1:

-
Tree-iter == [not] [pop] [R0]           [R1] genrec
-          == [not] [pop] [R0 [Tree-iter] R1] ifte
-
-
-

Let’s look at it in situ:

-
[key value left right] R0 [Tree-iter] R1
-
-
-
-

Processing the current node.

-

R0 is almost certainly going to use dup to make a copy of the -node and then dip on some function to process the copy with it:

-
[key value left right] [F] dupdip                 [Tree-iter] R1
-[key value left right]  F  [key value left right] [Tree-iter] R1
-
-
-

For example, if we’re getting all the keys F would be first:

-
R0 == [first] dupdip
-
-[key value left right] [first] dupdip                 [Tree-iter] R1
-[key value left right]  first  [key value left right] [Tree-iter] R1
-key                            [key value left right] [Tree-iter] R1
-
-
-
-
-

Recur

-

Now R1 needs to apply [Tree-iter] to left and right. If -we drop the key and value from the node using rest twice we are left -with an interesting situation:

-
key [key value left right] [Tree-iter] R1
-key [key value left right] [Tree-iter] [rest rest] dip
-key [key value left right] rest rest [Tree-iter]
-key [left right] [Tree-iter]
-
-
-

Hmm, will step do?

-
key [left right] [Tree-iter] step
-key left Tree-iter [right] [Tree-iter] step
-key left-keys [right] [Tree-iter] step
-key left-keys right Tree-iter
-key left-keys right-keys
-
-
-

Neat. So:

-
R1 == [rest rest] dip step
-
-
-
-
-
-

Putting it together

-

We have:

-
Tree-iter == [not] [pop] [[F] dupdip] [[rest rest] dip step] genrec
-
-
-

When I was reading this over I realized rest rest could go in -R0:

-
Tree-iter == [not] [pop] [[F] dupdip rest rest] [step] genrec
-
-
-

(And [step] genrec is such a cool and suggestive combinator!)

-
-
-

Parameterizing the F per-node processing function.

-
                [F] Tree-iter
-------------------------------------------------------
-   [not] [pop] [[F] dupdip rest rest] [step] genrec
-
-
-

Working backward:

-
[not] [pop] [[F] dupdip rest rest]            [step] genrec
-[not] [pop] [F]       [dupdip rest rest] cons [step] genrec
-[F] [not] [pop] roll< [dupdip rest rest] cons [step] genrec
-
-
-
-
-

Tree-iter

-
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("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter")
-
-
-
'b' 'a' 'c'
-
-
-
J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter")
-
-
-
23 88 44
-
-
-
-
-
-

Interlude: A Set-like Datastructure

-

We can use this to make a set-like datastructure by just setting values -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')
-
-
-
[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')
-
-
-
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 [] []]] []]] []]]
-
-
-

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')
-
-
-
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]
-
-
-
-
-

A Version of Tree-iter that does In-Order Traversal

-

If you look back to the non-empty case of the ``Tree-iter` -function <#Node-case-%5Bkey-value-left-right%5D>`__ we can design a -variant that first processes the left child, then the current node, then -the right child. This will allow us to traverse the tree in sort order.

-
Tree-iter-order == [not] [pop] [R0] [R1] genrec
-
-
-

To define R0 and R1 it helps to look at them as they will appear -when they run:

-
[key value left right] R0 [BTree-iter-order] R1
-
-
-
-

Process the left child.

-

Staring at this for a bit suggests dup third to start:

-
[key value left right] R0        [Tree-iter-order] R1
-[key value left right] dup third [Tree-iter-order] R1
-[key value left right] left      [Tree-iter-order] R1
-
-
-

Now maybe:

-
[key value left right] left [Tree-iter-order] [cons dip] dupdip
-[key value left right] left [Tree-iter-order]  cons dip [Tree-iter-order]
-[key value left right] [left Tree-iter-order]       dip [Tree-iter-order]
-left Tree-iter-order [key value left right]             [Tree-iter-order]
-
-
-
-
-

Process the current node.

-

So far, so good. Now we need to process the current node’s values:

-
left Tree-iter-order [key value left right] [Tree-iter-order] [[F] dupdip] dip
-left Tree-iter-order [key value left right] [F] dupdip [Tree-iter-order]
-left Tree-iter-order [key value left right] F [key value left right] [Tree-iter-order]
-
-
-

If F needs items from the stack below the left stuff it should have -cons’d them before beginning maybe? For functions like first -it works fine as-is.

-
left Tree-iter-order [key value left right] first [key value left right] [Tree-iter-order]
-left Tree-iter-order key [key value left right] [Tree-iter-order]
-
-
-
-
-

Process the right child.

-

First ditch the rest of the node and get the right child:

-
left Tree-iter-order key [key value left right] [Tree-iter-order] [rest rest rest first] dip
-left Tree-iter-order key right [Tree-iter-order]
-
-
-

Then, of course, we just need i to run Tree-iter-order on the -right side:

-
left Tree-iter-order key right [Tree-iter-order] i
-left Tree-iter-order key right Tree-iter-order
-
-
-
-
-

Defining Tree-iter-order

-

The result is a little awkward:

-
R1 == [cons dip] dupdip [[F] dupdip] dip [rest rest rest first] dip i
-
-
-

Let’s do a little semantic factoring:

-
fourth == rest rest rest first
-
-proc_left == [cons dip] dupdip
-proc_current == [[F] dupdip] dip
-proc_right == [fourth] dip i
-
-Tree-iter-order == [not] [pop] [dup third] [proc_left proc_current proc_right] genrec
-
-
-

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')
-
-
-DefinitionWrapper.add_definitions('''
-
-fourth == rest rest rest first
-
-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
-
-''', D)
-
-
-
J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order')
-
-
-
2 3 4 5 6 7 8 9
-
-
-

Parameterizing the [F] function is left as an exercise for the -reader.

-
-
-
-

Getting values by key

-

Let’s derive a function that accepts a tree and a key and returns the -value associated with that key.

-
   tree key Tree-get
------------------------
-        value
-
-
-

But what do we do if the key isn’t in the tree? In Python we might raise -a KeyError but I’d like to avoid exceptions in Joy if possible, and -here I think it’s possible. (Division by zero is an example of where I -think it’s probably better to let Python crash Joy. Sometimes the -machinery fails and you have to “stop the line”, I think.)

-

Let’s pass the buck to the caller by making the base case a given, you -have to decide for yourself what [E] should be.

-
   tree key [E] Tree-get
----------------------------- key in tree
-           value
-
-   tree key [E] Tree-get
----------------------------- key not in tree
-         [] key E
-
-
-
-

The base case []

-

As before, the stopping predicate just has to detect the empty list:

-
Tree-get == [pop not] [E] [R0] [R1] genrec
-
-
-

So we define:

-
Tree-get == [pop not] swap [R0] [R1] genrec
-
-
-

Note that this Tree-get creates a slightly different function than -itself and that function does the actual recursion. This kind of -higher-level programming is unusual in most languages but natural in -Joy.

-
tree key [E] [pop not] swap [R0] [R1] genrec
-tree key [pop not] [E] [R0] [R1] genrec
-
-
-

The anonymous specialized recursive function that will do the real work.

-
[pop not] [E] [R0] [R1] genrec
-
-
-
-
-

Node case [key value left right]

-

Now we need to figure out R0 and R1:

-
[key value left right] key R0 [BTree-get] R1
-
-
-

We want to compare the search key with the key in the node, and if they -are the same return the value, otherwise recur on one of the child -nodes. So it’s very similar to the above funtion, with [R0] == [] -and R1 == P [T>] [E] [T<] cmp:

-
[key value left right] key [BTree-get] P [T>] [E] [T<] cmp
-
-
-
-

Predicate

-
P == over [get-node-key] nullary
-get-node-key == pop popop first
-
-
-

The only difference is that get-node-key does one less pop -because there’s no value to discard.

-
-
-

Branches

-

Now we have to derive the branches:

-
[key_n value_n left right] key [BTree-get] T>
-[key_n value_n left right] key [BTree-get] E
-[key_n value_n left right] key [BTree-get] T<
-
-
-
-
-

Greater than and less than

-

The cases of T> and T< are similar to above but instead of using -infra we have to discard the rest of the structure:

-
   [key_n value_n left right] key [BTree-get] T>
----------------------------------------------------
-                       right  key  BTree-get
-
-
-

And:

-
   [key_n value_n left right] key [BTree-get] T<
----------------------------------------------------
-                  left        key  BTree-get
-
-
-

So:

-
T> == [fourth] dipd i
-T< == [third] dipd i
-
-
-

E.g.:

-
[key_n value_n left right]        key [BTree-get] [fourth] dipd i
-[key_n value_n left right] fourth key [BTree-get]               i
-                    right         key [BTree-get]               i
-                    right         key  BTree-get
-
-
-
-
-

Equal keys

-

Return the node’s value:

-
[key_n value_n left right] key [BTree-get] E == value_n
-
-E == popop second
-
-
-
-
-
-

Tree-get

-

So:

-
fourth == rest rest rest first
-get-node-key == pop popop first
-P == over [get-node-key] nullary
-T> == [fourth] dipd i
-T< == [third] dipd i
-E == popop second
-
-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...
-
-
-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')
-
-
-
'mike not in tree'
-
-
-
J('["gary" 23 [] []] "gary" [popop "err"] Tree-get')
-
-
-
23
-
-
-
J('''
-
-    [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step
-
-    'c' [popop 'not found'] Tree-get
-
-''')
-
-
-
2
-
-
-
J('''
-
-    [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step
-
-    'd' [popop 'not found'] Tree-get
-
-''')
-
-
-
'not found'
-
-
-
-
-
-

Tree-delete

-

Now let’s write a function that can return a tree datastructure with a -key, value pair deleted:

-
   tree key Tree-delete
----------------------------
-          tree
-
-
-

If the key is not in tree it just returns the tree unchanged.

-
-

Base case

-

Same as above.

-
Tree-Delete == [pop not] [pop] [R0] [R1] genrec
-
-
-
-
-

Recur

-

Now we get to figure out the recursive case. We need the node’s key to -compare and we need to carry the key into recursive branches. Let D -be shorthand for Tree-Delete:

-
D == Tree-Delete == [pop not] [pop] [R0] [R1] genrec
-
-[node_key node_value left right] key R0                   [D] R1
-[node_key node_value left right] key over  first swap dup [D] cons R1′
-[node_key node_value left right] key [...] first swap dup [D] cons R1′
-[node_key node_value left right] key node_key    swap dup [D] cons R1′
-[node_key node_value left right] node_key key         dup [D] cons R1′
-[node_key node_value left right] node_key key key         [D] cons R1′
-[node_key node_value left right] node_key key         [key D]      R1′
-
-
-

And then:

-
[node_key node_value left right] node_key key [key D] R1′
-[node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp
-[node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp
-[node_key node_value left right] [key D] node_key key       [T>] [E] [T<] cmp
-
-
-

So:

-
R0 == over first swap dup
-R1 == cons roll> [T>] [E] [T<] cmp
-
-
-
-
-

Compare Keys

-

The last line above:

-
[node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp
-
-
-

Then becomes one of these three:

-
[node_key node_value left right] [key D] T>
-[node_key node_value left right] [key D] E
-[node_key node_value left right] [key D] T<
-
-
-
-
-

Greater than case and less than case

-
   [node_key node_value left right] [F] T>
--------------------------------------------------
-   [node_key node_value (left F) right]
-
-
-   [node_key node_value left right] [F] T<
--------------------------------------------------
-   [node_key node_value left (right F)]
-
-
-

First, treating the node as a stack:

-
right left       node_value node_key [key D] dipd
-right left key D node_value node_key
-right left'      node_value node_key
-
-
-

Ergo:

-
[node_key node_value left right] [key D] [dipd] cons infra
-
-
-

So:

-
T> == [dipd] cons infra
-T< == [dipdd] cons infra
-
-
-
-
-

The else case

-

We have found the node in the tree where key equals node_key. We -need to replace the current node with something

-
   [node_key node_value left right] [key D] E
-------------------------------------------------
-                    tree
-
-
-

We have to handle three cases, so let’s use cond.

-
-

One or more child nodes are []

-

The first two cases are symmetrical: if we only have one non-empty child -node return it. If both child nodes are empty return an empty node.

-
E == [
-    [[pop third not] pop fourth]
-    [[pop fourth not] pop third]
-    [default]
-] cond
-
-
-
-
-

Both child nodes are non-empty.

-

If both child nodes are non-empty, we find the highest node in our lower -sub-tree, take its key and value to replace (delete) our own, then get -rid of it by recursively calling delete() on our lower sub-node with our -new key.

-

(We could also find the lowest node in our higher sub-tree and take its -key and value and delete it. I only implemented one of these two -symmetrical options. Over a lot of deletions this might make the tree -more unbalanced. Oh well.)

-

The initial structure of the default function:

-
default == [E′] cons infra
-
-[node_key node_value left right] [key D] default
-[node_key node_value left right] [key D] [E′] cons infra
-[node_key node_value left right] [[key D] E′]      infra
-
-right left node_value node_key [key D] E′
-
-
-

First things first, we no longer need this node’s key and value:

-
right left node_value node_key [key D] roll> popop E″
-right left [key D] node_value node_key       popop E″
-right left [key D]                                 E″
-
-
-
-
-

We have to we find the highest (right-most) node in our lower (left) sub-tree:

-
right left [key D] E″
-
-
-

Ditch the key:

-
right left [key D] rest E‴
-right left     [D]      E‴
-
-
-

Find the right-most node:

-
right left        [D] [dup W] dip E⁗
-right left dup  W [D]             E⁗
-right left left W [D]             E⁗
-
-
-

Consider:

-
left W
-
-
-

We know left is not empty:

-
[L_key L_value L_left L_right] W
-
-
-

We want to keep extracting the right node as long as it is not empty:

-
W.rightmost == [P] [B] while
-
-left W.rightmost W′
-
-
-

The predicate:

-
[L_key L_value L_left L_right] P
-[L_key L_value L_left L_right] fourth
-                      L_right
-
-
-

This can run on [] so must be guarded:

-
?fourth ==  [] [fourth] [] ifte
-
-
-

( if_not_empty == [] swap [] ifte ?fourth == [fourth] if_not_empty )

-

The body is just fourth:

-
left [?fourth] [fourth] while W′
-rightest                      W′
-
-
-

So:

-
W.rightmost == [?fourth] [fourth] while
-
-
-
-
-

Found right-most node in our left sub-tree

-

We know rightest is not empty:

-
[R_key R_value R_left R_right] W′
-[R_key R_value R_left R_right] W′
-[R_key R_value R_left R_right] uncons uncons pop
-R_key [R_value R_left R_right]        uncons pop
-R_key R_value [R_left R_right]               pop
-R_key R_value
-
-
-

So:

-
W == [?fourth] [fourth] while uncons uncons pop
-
-
-

And:

-
right left left W        [D] E⁗
-right left R_key R_value [D] E⁗
-
-
-
-
-

Replace current node key and value, recursively delete rightmost

-

Final stretch. We want to end up with something like:

-
right left [R_key D] i R_value R_key
-right left  R_key D    R_value R_key
-right left′            R_value R_key
-
-
-

If we adjust our definition of W to include over at the end:

-
W == [fourth] [fourth] while uncons uncons pop over
-
-
-

That will give us:

-
right left R_key R_value R_key [D] E⁗
-
-right left         R_key R_value R_key [D] cons dipd E⁗′
-right left         R_key R_value [R_key D]      dipd E⁗′
-right left R_key D R_key R_value                     E⁗′
-right left′        R_key R_value                     E⁗′
-right left′        R_key R_value                     swap
-right left′ R_value R_key
-
-
-

So:

-
E′ == roll> popop E″
-
-E″ == rest E‴
-
-E‴ == [dup W] dip E⁗
-
-E⁗ == cons dipdd swap
-
-
-

Substituting:

-
W == [fourth] [fourth] while uncons uncons pop over
-E′ == roll> popop rest [dup W] dip cons dipd swap
-E == [
-    [[pop third not] pop fourth]
-    [[pop fourth not] pop third]
-    [[E′] cons infra]
-] cond
-
-
-

Minor rearrangement, move dup into W:

-
W == dup [fourth] [fourth] while uncons uncons pop over
-E′ == roll> popop rest [W] dip cons dipd swap
-E == [
-    [[pop third not] pop fourth]
-    [[pop fourth not] pop third]
-    [[E′] cons infra]
-] cond
-
-
-
-
-
-

Refactoring

-
W.rightmost == [fourth] [fourth] while
-W.unpack == uncons uncons pop
-W == dup W.rightmost W.unpack over
-E.clear_stuff == roll> popop rest
-E.delete == cons dipd
-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
-BTree-Delete == [pop not] swap [R0] [R1] genrec
-
-
-

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 ")
-
-
-
['a' 23 [] ['b' 88 [] []]]
-
-
-
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ")
-
-
-
['a' 23 [] ['c' 44 [] []]]
-
-
-
J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ")
-
-
-
['b' 88 [] ['c' 44 [] []]]
-
-
-
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')
-
-
-
[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 ")
-
-
-
[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 ")
-
-
-
[3 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]]
-
-
-
-
-
-

Appendix: The source code.

-
fourth == rest_two rest first
-?fourth == [] [fourth] [] ifte
-first_two == uncons uncons pop
-ccons == cons cons
-cinf == cons infra
-rest_two == rest rest
-
-_Tree_T> == [dipd] cinf
-_Tree_T< == [dipdd] cinf
-
-_Tree_add_P == over [popop popop first] nullary
-_Tree_add_T> == ccons _Tree_T<
-_Tree_add_T< == ccons _Tree_T>
-_Tree_add_Ee == pop swap roll< rest_two ccons
-_Tree_add_R == _Tree_add_P [_Tree_add_T>] [_Tree_add_Ee] [_Tree_add_T<] cmp
-_Tree_add_E == [pop] dipd Tree-new
-
-_Tree_iter_order_left == [cons dip] dupdip
-_Tree_iter_order_current == [[F] dupdip] dip
-_Tree_iter_order_right == [fourth] dip i
-_Tree_iter_order_R == _Tree_iter_order_left _Tree_iter_order_current _Tree_iter_order_right
-
-_Tree_get_P == over [pop popop first] nullary
-_Tree_get_T> == [fourth] dipd i
-_Tree_get_T< == [third] dipd i
-_Tree_get_E == popop second
-_Tree_get_R == _Tree_get_P [_Tree_get_T>] [_Tree_get_E] [_Tree_get_T<] cmp
-
-_Tree_delete_rightmost == [?fourth] [fourth] while
-_Tree_delete_clear_stuff == roll> popop rest
-_Tree_delete_del == dip cons dipd swap
-_Tree_delete_W == dup _Tree_delete_rightmost first_two over
-_Tree_delete_E.0 == _Tree_delete_clear_stuff [_Tree_delete_W] _Tree_delete_del
-_Tree_delete_E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[_Tree_delete_E.0] cinf]] cond
-_Tree_delete_R0 == over first swap dup
-_Tree_delete_R1 == cons roll> [_Tree_T>] [_Tree_delete_E] [_Tree_T<] cmp
-
-Tree-new == swap [[] []] ccons
-Tree-add == [popop not] [_Tree_add_E] [] [_Tree_add_R] genrec
-Tree-iter == [not] [pop] roll< [dupdip rest_two] cons [step] genrec
-Tree-iter-order == [not] [pop] [dup third] [_Tree_iter_order_R] genrec
-Tree-get == [pop not] swap [] [_Tree_get_R] genrec
-Tree-delete == [pop not] [pop] [_Tree_delete_R0] [_Tree_delete_R1] genrec
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Quadratic.html b/docs/sphinx_docs/_build/html/notebooks/Quadratic.html deleted file mode 100644 index 86fe364..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Quadratic.html +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - - - - Quadratic formula — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
from notebook_preamble import J, V, define
-
-
-
-

Quadratic formula

-

Cf. -jp-quadratic.html

-
   -b ± sqrt(b^2 - 4 * a * c)
---------------------------------
-            2 * a
-
-
-

\(\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}\)

-
-

Write a straightforward program with variable names.

-

This math translates to Joy code in a straightforward manner. We are -going to use named variables to keep track of the arguments, then write -a definition without them.

-
-

-b

-
b neg
-
-
-
-
-

sqrt(b^2 - 4 * a * c)

-
b sqr 4 a c * * - sqrt
-
-
-
-
-

/2a

-
a 2 * /
-
-
-
-
-

±

-

There is a function pm that accepts two values on the stack and -replaces them with their sum and difference.

-
pm == [+] [-] cleave popdd
-
-
-
-
-

Putting Them Together

-
b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2
-
-
-

We use app2 to compute both roots by using a quoted program -[2a /] built with cons.

-
-
-
-

Derive a definition.

-

Working backwards we use dip and dipd to extract the code from -the variables:

-
b             neg  b      sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
-b            [neg] dupdip sqr 4 a c   * * - sqrt pm a    2 * [/] cons app2
-b a c       [[neg] dupdip sqr 4] dipd * * - sqrt pm a    2 * [/] cons app2
-b a c a    [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
-b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
-
-
-

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

Let’s try it out:

-
J('3 1 1 quadratic')
-
-
-
-0.3819660112501051 -2.618033988749895
-
-
-

If you look at the Joy evaluation trace you can see that the first few -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.

-
V('-5 1 4 quadratic')
-
-
-
                                                   . -5 1 4 quadratic
-                                                -5 . 1 4 quadratic
-                                              -5 1 . 4 quadratic
-                                            -5 1 4 . quadratic
-                                            -5 1 4 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
-                                          -5 1 4 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2
--5 1 4 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2
-                                            -5 1 4 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [/] cons app2
-                       -5 1 4 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [/] cons app2
-                                                -5 . [neg] dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                          -5 [neg] . dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                                -5 . neg -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                                 5 . -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                              5 -5 . sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                              5 -5 . dup mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                           5 -5 -5 . mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                              5 25 . 4 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                            5 25 4 . 1 4 * * - sqrt pm 1 2 * [/] cons app2
-                                          5 25 4 1 . 4 * * - sqrt pm 1 2 * [/] cons app2
-                                        5 25 4 1 4 . * * - sqrt pm 1 2 * [/] cons app2
-                                          5 25 4 4 . * - sqrt pm 1 2 * [/] cons app2
-                                           5 25 16 . - sqrt pm 1 2 * [/] cons app2
-                                               5 9 . sqrt pm 1 2 * [/] cons app2
-                                             5 3.0 . pm 1 2 * [/] cons app2
-                                           8.0 2.0 . 1 2 * [/] cons app2
-                                         8.0 2.0 1 . 2 * [/] cons app2
-                                       8.0 2.0 1 2 . * [/] cons app2
-                                         8.0 2.0 2 . [/] cons app2
-                                     8.0 2.0 2 [/] . cons app2
-                                     8.0 2.0 [2 /] . app2
-                                       [8.0] [2 /] . infra first [2.0] [2 /] infra first
-                                               8.0 . 2 / [] swaack first [2.0] [2 /] infra first
-                                             8.0 2 . / [] swaack first [2.0] [2 /] infra first
-                                               4.0 . [] swaack first [2.0] [2 /] infra first
-                                            4.0 [] . swaack first [2.0] [2 /] infra first
-                                             [4.0] . first [2.0] [2 /] infra first
-                                               4.0 . [2.0] [2 /] infra first
-                                         4.0 [2.0] . [2 /] infra first
-                                   4.0 [2.0] [2 /] . infra first
-                                               2.0 . 2 / [4.0] swaack first
-                                             2.0 2 . / [4.0] swaack first
-                                               1.0 . [4.0] swaack first
-                                         1.0 [4.0] . swaack first
-                                         4.0 [1.0] . first
-                                           4.0 1.0 .
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Recursion_Combinators.html b/docs/sphinx_docs/_build/html/notebooks/Recursion_Combinators.html deleted file mode 100644 index 385778c..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Recursion_Combinators.html +++ /dev/null @@ -1,682 +0,0 @@ - - - - - - - - - Recursion Combinators — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
from notebook_preamble import D, DefinitionWrapper, J, V, define
-
-
-
-

Recursion Combinators

-

This article describes the genrec combinator, how to use it, and -several generic specializations.

-
                      [if] [then] [rec1] [rec2] genrec
----------------------------------------------------------------------
-   [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte
-
-
-

From “Recursion Theory and Joy” (j05cmp.html) by Manfred von Thun:

-
-

“The genrec combinator takes four program parameters in addition to -whatever data parameters it needs. Fourth from the top is an if-part, -followed by a then-part. If the if-part yields true, then the -then-part is executed and the combinator terminates. The other two -parameters are the rec1-part and the rec2-part. If the if-part yields -false, the rec1-part is executed. Following that the four program -parameters and the combinator are again pushed onto the stack bundled -up in a quoted form. Then the rec2-part is executed, where it will -find the bundled form. Typically it will then execute the bundled -form, either with i or with app2, or some other combinator.”

-
-
-

Designing Recursive Functions

-

The way to design one of these is to fix your base case and test and -then treat R1 and R2 as an else-part “sandwiching” a quotation -of the whole function.

-

For example, given a (general recursive) function F:

-
F == [I] [T] [R1]   [R2] genrec
-  == [I] [T] [R1 [F] R2] ifte
-
-
-

If the [I] predicate is false you must derive R1 and R2 -from:

-
... R1 [F] R2
-
-
-

Set the stack arguments in front and figure out what R1 and R2 -have to do to apply the quoted [F] in the proper way.

-
-
-

Primitive Recursive Functions

-

Primitive recursive functions are those where R2 == i.

-
P == [I] [T] [R] primrec
-  == [I] [T] [R [P] i] ifte
-  == [I] [T] [R P] ifte
-
-
-
-
-

Hylomorphism

-

A -hylomorphism -is a recursive function H :: A -> C that converts a value of type -A into a value of type C by means of:

-
    -
  • A generator G :: A -> (B, A)

  • -
  • A combiner F :: (B, C) -> C

  • -
  • A predicate P :: A -> Bool to detect the base case

  • -
  • A base case value c :: C

  • -
  • Recursive calls (zero or more); it has a “call stack in the form of a -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 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
-
-
-

Cf. “Bananas, Lenses, & Barbed -Wire”

-

Note that during evaluation of H() the intermediate b values are -stored in the Python call stack. This is what is meant by “call stack in -the form of a cons list”.

-
-
-

Hylomorphism in Joy

-

We can define a combinator hylomorphism that will make a -hylomorphism combinator H from constituent parts.

-
H == [P] c [G] [F] hylomorphism
-
-
-

The function H is recursive, so we start with ifte and set the -else-part to some function J that will contain a quoted copy of -H. (The then-part just discards the leftover a and replaces it -with the base case value c.)

-
H == [P] [pop c] [J] ifte
-
-
-

The else-part J gets just the argument a on the stack.

-
a J
-a G              The first thing to do is use the generator G
-aa b             which produces b and a new aa
-aa b [H] dip     we recur with H on the new aa
-aa H b F         and run F on the result.
-
-
-

This gives us a definition for J.

-
J == G [H] dip F
-
-
-

Plug it in and convert to genrec.

-
H == [P] [pop c] [G [H] dip F] ifte
-H == [P] [pop c] [G]   [dip F] genrec
-
-
-

This is the form of a hylomorphism in Joy, which nicely illustrates that -it is a simple specialization of the general recursion combinator.

-
H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec
-
-
-
-
-

Derivation of hylomorphism combinator

-

Now we just need to derive a definition that builds the genrec -arguments out of the pieces given to the hylomorphism combinator.

-
   [P]      c  [G]     [F] hylomorphism
-------------------------------------------
-   [P] [pop c] [G] [dip F] genrec
-
-
-

Working in reverse:

-
    -
  • Use swoncat twice to decouple [c] and [F].

  • -
  • Use unit to dequote c.

  • -
  • Use dipd to untangle [unit [pop] swoncat] from the givens.

  • -
-

So:

-
H == [P] [pop c]              [G]                  [dip F] genrec
-     [P] [c]    [pop] swoncat [G]        [F] [dip] swoncat genrec
-     [P] c unit [pop] swoncat [G]        [F] [dip] swoncat genrec
-     [P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec
-
-
-

At this point all of the arguments (givens) to the hylomorphism are to -the left so we have a definition for hylomorphism:

-
hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec
-
-
-
define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec')
-
-
-
-

Example: Finding Triangular Numbers

-

Let’s write a function that, given a positive integer, returns the sum -of all positive integers less than that one. (In this case the types -A, B and C are all int.)

-

To sum a range of integers from 0 to n - 1:

-
    -
  • [P] is [1 <=]

  • -
  • c is 0

  • -
  • [G] is [-- dup]

  • -
  • [F] is [+]

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

Let’s try it:

-
J('5 triangular_number')
-
-
-
10
-
-
-
J('[0 1 2 3 4 5 6] [triangular_number] map')
-
-
-
[0 0 1 3 6 10 15]
-
-
-
-
-
-

Four Specializations

-

There are at least four kinds of recursive combinator, depending on two -choices. The first choice is whether the combiner function F should -be evaluated during the recursion or pushed into the pending expression -to be “collapsed” at the end. The second choice is whether the combiner -needs to operate on the current value of the datastructure or the -generator’s output, in other words, whether F or G should run -first in the recursive branch.

-
H1 ==        [P] [pop c] [G             ] [dip F] genrec
-H2 == c swap [P] [pop]   [G [F]    dip  ] [i]     genrec
-H3 ==        [P] [pop c] [  [G] dupdip  ] [dip F] genrec
-H4 == c swap [P] [pop]   [  [F] dupdip G] [i]     genrec
-
-
-

The working of the generator function G differs slightly for each. -Consider the recursive branches:

-
... a G [H1] dip F                w/ a G == a′ b
-
-... c a G [F] dip H2                 a G == b  a′
-
-... a [G] dupdip [H3] dip F          a G == a′
-
-... c a [F] dupdip G H4              a G == a′
-
-
-

The following four sections illustrate how these work, omitting the -predicate evaluation.

-
-

H1

-
H1 == [P] [pop c] [G] [dip F] genrec
-
-
-

Iterate n times.

-
... a  G [H1] dip F
-... a′ b [H1] dip F
-... a′ H1 b F
-... a′ G [H1] dip F b F
-... a″ b′ [H1] dip F b F
-... a″ H1 b′ F b F
-... a″ G [H1] dip F b′ F b F
-... a‴ b″ [H1] dip F b′ F b F
-... a‴ H1 b″ F b′ F b F
-... a‴ pop c b″ F b′ F b F
-... c b″ F b′ F b F
-... d      b′ F b F
-... d′          b F
-... d″
-
-
-

This form builds up a pending expression (continuation) that contains -the intermediate results along with the pending combiner functions. When -the base case is reached the last term is replaced by the identity value -c and the continuation “collapses” into the final result using the -combiner F.

-
-
-

H2

-

When you can start with the identity value c on the stack and the -combiner F can operate as you go using the intermediate results -immediately rather than queuing them up, use this form. An important -difference is that the generator function must return its results in the -reverse order.

-
H2 == c swap [P] [pop] [G [F] dip] primrec
-
-... c a G  [F] dip H2
-... c b a′ [F] dip H2
-... c b F a′ H2
-... d     a′ H2
-... d a′ G  [F] dip H2
-... d b′ a″ [F] dip H2
-... d b′ F a″ H2
-... d′     a″ H2
-... d′ a″ G  [F] dip H2
-... d′ b″ a‴ [F] dip H2
-... d′ b″ F a‴ H2
-... d″      a‴ H2
-... d″ a‴ pop
-... d″
-
-
-
-
-

H3

-

If you examine the traces above you’ll see that the combiner F only -gets to operate on the results of G, it never “sees” the first value -a. If the combiner and the generator both need to work on the -current value then dup must be used, and the generator must produce -one item instead of two (the b is instead the duplicate of a.)

-
H3 == [P] [pop c] [[G] dupdip] [dip F] genrec
-
-... a [G] dupdip [H3] dip F
-... a  G  a      [H3] dip F
-... a′    a      [H3] dip F
-... a′ H3 a               F
-... a′ [G] dupdip [H3] dip F a F
-... a′  G  a′     [H3] dip F a F
-... a″     a′     [H3] dip F a F
-... a″ H3  a′              F a F
-... a″ [G] dupdip [H3] dip F a′ F a F
-... a″  G    a″   [H3] dip F a′ F a F
-... a‴       a″   [H3] dip F a′ F a F
-... a‴ H3    a″            F a′ F a F
-... a‴ pop c a″ F a′ F a F
-...        c a″ F a′ F a F
-...        d      a′ F a F
-...        d′          a F
-...        d″
-
-
-
-
-

H4

-

And, last but not least, if you can combine as you go, starting with -c, and the combiner F needs to work on the current item, this is -the form:

-
H4 == c swap [P] [pop] [[F] dupdip G] primrec
-
-... c  a  [F] dupdip G H4
-... c  a   F  a      G H4
-... d         a      G H4
-... d  a′              H4
-... d  a′ [F] dupdip G H4
-... d  a′  F  a′     G H4
-... d′        a′     G H4
-... d′ a″              H4
-... d′ a″ [F] dupdip G H4
-... d′ a″  F  a″     G H4
-... d″        a″     G H4
-... d″ a‴              H4
-... d″ a‴ pop
-... d″
-
-
-
-
-
-

Anamorphism

-

An anamorphism can be defined as a hylomorphism that uses [] for -c and swons for F. An anamorphic function builds a list of -values.

-
A == [P] [] [G] [swons] hylomorphism
-
-
-
-

range et. al. An example of an anamorphism is the range function which generates the list of integers from 0 to n - 1 given n.

-

Each of the above variations can be used to make four slightly different -range functions.

-
-

range with H1

-
H1 == [P]    [pop c]  [G]      [dip F]     genrec
-   == [0 <=] [pop []] [-- dup] [dip swons] genrec
-
-
-
define('range == [0 <=] [] [-- dup] [swons] hylomorphism')
-
-
-
J('5 range')
-
-
-
[4 3 2 1 0]
-
-
-
-
-

range with H2

-
H2 == c  swap [P]    [pop] [G      [F]     dip] primrec
-   == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec
-
-
-
define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec')
-
-
-
J('5 range_reverse')
-
-
-
[0 1 2 3 4]
-
-
-
-
-

range with H3

-
H3 == [P]    [pop c]  [[G]  dupdip] [dip F]     genrec
-   == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec
-
-
-
define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec')
-
-
-
J('5 ranger')
-
-
-
[5 4 3 2 1]
-
-
-
-
-

range with H4

-
H4 == c  swap [P]    [pop] [[F]     dupdip G ] primrec
-   == [] swap [0 <=] [pop] [[swons] dupdip --] primrec
-
-
-
define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec')
-
-
-
J('5 ranger_reverse')
-
-
-
[1 2 3 4 5]
-
-
-

Hopefully this illustrates the workings of the variations. For more -insight you can run the cells using the V() function instead of the -J() function to get a trace of the Joy evaluation.

-
-
-
-
-

Catamorphism

-

A catamorphism can be defined as a hylomorphism that uses -[uncons swap] for [G] and [[] =] (or just [not]) for the -predicate [P]. A catamorphic function tears down a list term-by-term -and makes some new value.

-
C == [not] c [uncons swap] [F] hylomorphism
-
-
-
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')
-
-
-
J('[5 4 3 2 1] sum')
-
-
-
15
-
-
-
-

The step combinator

-

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

-
J('[step] help')
-
-
-
Run a quoted program on each item in a sequence.
-::
-
-        ... [] [Q] . step
-     -----------------------
-               ... .
-
-
-       ... [a] [Q] . step
-    ------------------------
-             ... a . Q
-
-
-     ... [a b c] [Q] . step
-  ----------------------------------------
-               ... a . Q [b c] [Q] step
-
-The step combinator executes the quotation on each member of the list
-on top of the stack.
-
-
-
define('sum == 0 swap [+] step')
-
-
-
J('[5 4 3 2 1] sum')
-
-
-
15
-
-
-
-
-
-

Example: Factorial Function

-

For the Factorial function:

-
H4 == c swap [P] [pop] [[F] dupdip G] primrec
-
-
-

With:

-
c == 1
-F == *
-G == --
-P == 1 <=
-
-
-
define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec')
-
-
-
J('5 factorial')
-
-
-
120
-
-
-
-
-

Example: tails

-

An example of a paramorphism for lists given in the “Bananas…” -paper -is tails which returns the list of “tails” of a list.

-
    [1 2 3] tails
---------------------
-   [[] [3] [2 3]]
-
-
-

We can build as we go, and we want F to run after G, so we use -pattern H2:

-
H2 == c swap [P] [pop] [G [F] dip] primrec
-
-
-

We would use:

-
c == []
-F == swons
-G == rest dup
-P == not
-
-
-
define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec')
-
-
-
J('[1 2 3] tails')
-
-
-
[[] [3] [2 3]]
-
-
-
-
-

Conclusion: Patterns of Recursion

-

Our story so far…

-
-

Hylo-, Ana-, Cata-

-
H == [P  ] [pop c ] [G          ] [dip F        ] genrec
-A == [P  ] [pop []] [G          ] [dip swap cons] genrec
-C == [not] [pop c ] [uncons swap] [dip F        ] genrec
-
-
-
-
-

Para-, ?-, ?-

-
P == c  swap [P  ] [pop] [[F        ] dupdip G          ] primrec
-? == [] swap [P  ] [pop] [[swap cons] dupdip G          ] primrec
-? == c  swap [not] [pop] [[F        ] dupdip uncons swap] primrec
-
-
-
-
-
-

Appendix: Fun with Symbols

-
|[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)]
-
-
-

“Bananas, Lenses, & Barbed -Wire”

-
(|...|)  [(...)]  [<...>]
-
-
-

I think they are having slightly too much fun with the symbols. However, -“Too much is always better than not enough.”

-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Replacing.html b/docs/sphinx_docs/_build/html/notebooks/Replacing.html deleted file mode 100644 index f1fcbbc..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Replacing.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - - - - Replacing Functions in the Dictionary — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Replacing Functions in the Dictionary

-

For now, there is no way to define new functions from within the Joy -language. All functions (and the interpreter) all accept and return a -dictionary parameter (in addition to the stack and expression) so that -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
-
-
-
-

A long trace

-
V('[23 18] average')
-
-
-
                                  . [23 18] average
-                          [23 18] . average
-                          [23 18] . [sum 1.0 *] [size] cleave /
-              [23 18] [sum 1.0 *] . [size] cleave /
-       [23 18] [sum 1.0 *] [size] . cleave /
-       [23 18] [sum 1.0 *] [size] . [i] app2 [popd] dip /
-   [23 18] [sum 1.0 *] [size] [i] . app2 [popd] dip /
-[23 18] [[sum 1.0 *] [23 18]] [i] . infra first [[size] [23 18]] [i] infra first [popd] dip /
-              [23 18] [sum 1.0 *] . i [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                          [23 18] . sum 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                               41 . 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                           41 1.0 . * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                             41.0 . [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                   41.0 [[23 18]] . swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                   [23 18] [41.0] . first [[size] [23 18]] [i] infra first [popd] dip /
-                     [23 18] 41.0 . [[size] [23 18]] [i] infra first [popd] dip /
-    [23 18] 41.0 [[size] [23 18]] . [i] infra first [popd] dip /
-[23 18] 41.0 [[size] [23 18]] [i] . infra first [popd] dip /
-                   [23 18] [size] . i [41.0 [23 18]] swaack first [popd] dip /
-                          [23 18] . size [41.0 [23 18]] swaack first [popd] dip /
-                          [23 18] . 0 swap [pop ++] step [41.0 [23 18]] swaack first [popd] dip /
-                        [23 18] 0 . swap [pop ++] step [41.0 [23 18]] swaack first [popd] dip /
-                        0 [23 18] . [pop ++] step [41.0 [23 18]] swaack first [popd] dip /
-               0 [23 18] [pop ++] . step [41.0 [23 18]] swaack first [popd] dip /
-                    0 23 [pop ++] . i [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip /
-                             0 23 . pop ++ [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip /
-                                0 . ++ [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip /
-                                1 . [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip /
-                           1 [18] . [pop ++] step [41.0 [23 18]] swaack first [popd] dip /
-                  1 [18] [pop ++] . step [41.0 [23 18]] swaack first [popd] dip /
-                    1 18 [pop ++] . i [41.0 [23 18]] swaack first [popd] dip /
-                             1 18 . pop ++ [41.0 [23 18]] swaack first [popd] dip /
-                                1 . ++ [41.0 [23 18]] swaack first [popd] dip /
-                                2 . [41.0 [23 18]] swaack first [popd] dip /
-                 2 [41.0 [23 18]] . swaack first [popd] dip /
-                 [23 18] 41.0 [2] . first [popd] dip /
-                   [23 18] 41.0 2 . [popd] dip /
-            [23 18] 41.0 2 [popd] . dip /
-                     [23 18] 41.0 . popd 2 /
-                             41.0 . 2 /
-                           41.0 2 . /
-                             20.5 .
-
-
-
-
-

Replacing size with a Python version

-

Both sum and size each convert a sequence to a single value.

-
 sum == 0 swap [+] step
-size == 0 swap [pop ++] step
-
-
-

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
-
-
-@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
-
-
-
-
-

A shorter trace

-

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

-
V('[23 18] average')
-
-
-
                                  . [23 18] average
-                          [23 18] . average
-                          [23 18] . [sum 1.0 *] [size] cleave /
-              [23 18] [sum 1.0 *] . [size] cleave /
-       [23 18] [sum 1.0 *] [size] . cleave /
-       [23 18] [sum 1.0 *] [size] . [i] app2 [popd] dip /
-   [23 18] [sum 1.0 *] [size] [i] . app2 [popd] dip /
-[23 18] [[sum 1.0 *] [23 18]] [i] . infra first [[size] [23 18]] [i] infra first [popd] dip /
-              [23 18] [sum 1.0 *] . i [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                          [23 18] . sum 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                               41 . 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                           41 1.0 . * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                             41.0 . [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                   41.0 [[23 18]] . swaack first [[size] [23 18]] [i] infra first [popd] dip /
-                   [23 18] [41.0] . first [[size] [23 18]] [i] infra first [popd] dip /
-                     [23 18] 41.0 . [[size] [23 18]] [i] infra first [popd] dip /
-    [23 18] 41.0 [[size] [23 18]] . [i] infra first [popd] dip /
-[23 18] 41.0 [[size] [23 18]] [i] . infra first [popd] dip /
-                   [23 18] [size] . i [41.0 [23 18]] swaack first [popd] dip /
-                          [23 18] . size [41.0 [23 18]] swaack first [popd] dip /
-                                2 . [41.0 [23 18]] swaack first [popd] dip /
-                 2 [41.0 [23 18]] . swaack first [popd] dip /
-                 [23 18] 41.0 [2] . first [popd] dip /
-                   [23 18] 41.0 2 . [popd] dip /
-            [23 18] 41.0 2 [popd] . dip /
-                     [23 18] 41.0 . popd 2 /
-                             41.0 . 2 /
-                           41.0 2 . /
-                             20.5 .
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Square_Spiral.html b/docs/sphinx_docs/_build/html/notebooks/Square_Spiral.html deleted file mode 100644 index a6033ad..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Square_Spiral.html +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - - - - Square Spiral Example Joy Code — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
from notebook_preamble import J, V, define
-
-
-
-

Square Spiral Example Joy Code

-

Here is the example of Joy code from the README file:

-
[[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte
-
-
-

It might seem unreadable but with a little familiarity it becomes just -as legible as any other notation. Some layout helps:

-
[   [[abs] ii <=]
-    [
-        [<>] [pop !-] ||
-    ] &&
-]
-[[    !-] [[++]] [[--]] ifte dip]
-[[pop !-]  [--]   [++]  ifte    ]
-ifte
-
-
-

This function accepts two integers on the stack and increments or -decrements one of them such that the new pair of numbers is the next -coordinate pair in a square spiral (like the kind used to construct an -Ulam Spiral).

-
-

Original Form

-

It’s adapted from the original code on -StackOverflow:

-
-

If all you’re trying to do is generate the first N points in the -spiral (without the original problem’s constraint of masking to an N -x M region), the code becomes very simple:

-
-
void spiral(const int N)
-{
-    int x = 0;
-    int y = 0;
-    for(int i = 0; i < N; ++i)
-    {
-        cout << x << '\t' << y << '\n';
-        if(abs(x) <= abs(y) && (x != y || x >= 0))
-            x += ((y >= 0) ? 1 : -1);
-        else
-            y += ((x >= 0) ? -1 : 1);
-    }
-}
-
-
-
-
-

Translation to Joy

-

I’m going to make a function that take two ints (x and y) and -generates the next pair, we’ll turn it into a generator later using the -x combinator.

-
-

First Boolean Predicate

-

We need a function that computes abs(x) <= abs(y), we can use ii -to apply abs to both values and then compare them with <=:

-
[abs] ii <=
-
-
-

I’ve defined two short-circuiting Boolean combinators && and || -that each accept two quoted predicate programs, run the first, and -conditionally run the second only if required (to compute the final -Boolean value). They run their predicate arguments nullary.

-
define('&& [nullary] cons [nullary [0]] dip branch')
-define('|| [nullary] cons [nullary] dip [1] branch')
-
-
-

Given those, we can define x != y || x >= 0 as:

-
[<>] [pop 0 >=] ||
-
-
-

And (abs(x) <= abs(y) && (x != y || x >= 0)) as:

-
[[abs] ii <=] [[<>] [pop 0 >=] ||] &&
-
-
-

It’s a little rough, but, as I say, with a little familiarity it becomes -legible.

-
-
-

The Increment / Decrement Branches

-

Turning to the branches of the main if statement:

-
x += ((y >= 0) ? 1 : -1);
-
-
-

Rewrite as a hybrid (pseudo-code) ifte expression:

-
[y >= 0] [x += 1] [X -= 1] ifte
-
-
-

Change each C phrase to Joy code:

-
[0 >=] [[++] dip] [[--] dip] ifte
-
-
-

Factor out the dip from each branch:

-
[0 >=] [[++]] [[--]] ifte dip
-
-
-

Similar logic applies to the other branch:

-
y += ((x >= 0) ? -1 : 1);
-
-[x >= 0] [y -= 1] [y += 1] ifte
-
-[pop 0 >=] [--] [++] ifte
-
-
-
-
-

“Not Negative”

-
define('!- 0 >=')
-
-
-
-
-
-

Putting the Pieces Together

-

We can assemble the three functions we just defined in quotes and give -them them to the ifte combinator. With some arrangement to show off -the symmetry of the two branches, we have:

-
[[[abs] ii <=] [[<>] [pop !-] ||] &&]
-[[    !-] [[++]] [[--]] ifte dip]
-[[pop !-]  [--]   [++]  ifte    ]
-ifte
-
-
-

As I was writing this up I realized that, since the && combinator -doesn’t consume the stack (below its quoted args), I can unquote the -predicate, swap the branches, and use the branch combinator instead -of ifte:

-
[[abs] ii <=] [[<>] [pop !-] ||] &&
-[[pop !-]  [--]   [++]  ifte    ]
-[[    !-] [[++]] [[--]] ifte dip]
-branch
-
-
-
define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte')
-
-
-

Let’s try it out:

-
J('0 0 spiral_next')
-
-
-
1 0
-
-
-
J('1 0 spiral_next')
-
-
-
1 -1
-
-
-
J('1 -1 spiral_next')
-
-
-
0 -1
-
-
-
J('0 -1 spiral_next')
-
-
-
-1 -1
-
-
-
-
-

Turning it into a Generator with x

-

It can be used with the x combinator to make a kind of generator for -spiral square coordinates.

-

We can use codireco to make a generator

-
codireco ::= cons dip rest cons
-
-
-

It will look like this:

-
[value [F] codireco]
-
-
-

Here’s a trace of how it works:

-
           [0 [dup ++] codireco] . x
-           [0 [dup ++] codireco] . 0 [dup ++] codireco
-         [0 [dup ++] codireco] 0 . [dup ++] codireco
-[0 [dup ++] codireco] 0 [dup ++] . codireco
-[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons
-[0 [dup ++] codireco] [0 dup ++] . dip rest cons
-                                 . 0 dup ++ [0 [dup ++] codireco] rest cons
-                               0 . dup ++ [0 [dup ++] codireco] rest cons
-                             0 0 . ++ [0 [dup ++] codireco] rest cons
-                             0 1 . [0 [dup ++] codireco] rest cons
-       0 1 [0 [dup ++] codireco] . rest cons
-         0 1 [[dup ++] codireco] . cons
-         0 [1 [dup ++] codireco] .
-
-
-

But first we have to change the spiral_next function to work on a -quoted pair of integers, and leave a copy of the pair on the stack. -From:

-
   y x spiral_next
----------------------
-        y' x'
-
-
-

to:

-
   [x y] [spiral_next] infra
--------------------------------
-           [x' y']
-
-
-
J('[0 0] [spiral_next] infra')
-
-
-
[0 1]
-
-
-

So our generator is:

-
[[x y] [dup [spiral_next] infra] codireco]
-
-
-

Or rather:

-
[[0 0] [dup [spiral_next] infra] codireco]
-
-
-

There is a function make_generator that will build the generator for -us out of the value and stepper function:

-
   [0 0] [dup [spiral_next] infra] make_generator
-----------------------------------------------------
-     [[0 0] [dup [spiral_next] infra] codireco]
-
-
-

Here it is in action:

-
J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop')
-
-
-
[0 0] [0 1] [-1 1] [-1 0]
-
-
-

Four x combinators, four pairs of coordinates.

-
-
-

Conclusion

-

So that’s an example of Joy code. It’s a straightforward translation of -the original. It’s a little long for a single definition, you might -break it up like so:

-
     _spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] &&
-
-     _spn_T ::= [    !-] [[++]] [[--]] ifte dip
-     _spn_E ::= [pop !-]  [--]   [++]  ifte
-
-spiral_next ::= _spn_P [_spn_E] [_spn_T] branch
-
-
-

This way it’s easy to see that the function is a branch with two -quasi-symmetrical paths.

-

We then used this function to make a simple generator of coordinate -pairs, where the next pair in the series can be generated at any time by -using the x combinator on the generator (which is just a quoted -expression containing a copy of the current pair and the “stepper -function” to generate the next pair from that.)

-
define('_spn_P [[abs] ii <=] [[<>] [pop !-] ||] &&')
-define('_spn_T [!-] [[++]] [[--]] ifte dip')
-define('_spn_E [pop !-] [--] [++] ifte')
-define('spiral_next _spn_P [_spn_E] [_spn_T] branch')
-
-
-
V('23 18 spiral_next')
-
-
-
                                                               . 23 18 spiral_next
-                                                            23 . 18 spiral_next
-                                                         23 18 . spiral_next
-                                                         23 18 . _spn_P [_spn_E] [_spn_T] branch
-                                                         23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
-                                           23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch
-                        23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch
-                        23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
-              23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch
-              23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch
-23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch
-                                           23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                           23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                   23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                   23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                         23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                 23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                   23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                         23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                   23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                   23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                             23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                   23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                            23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                            23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                         23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                   23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                         23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                         23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                         False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                 False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                 23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                                   23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                                               23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch
-                  23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch
-                                                         23 18 . 0 [_spn_E] [_spn_T] branch
-                                                       23 18 0 . [_spn_E] [_spn_T] branch
-                                              23 18 0 [_spn_E] . [_spn_T] branch
-                                     23 18 0 [_spn_E] [_spn_T] . branch
-                                                         23 18 . _spn_E
-                                                         23 18 . [pop !-] [--] [++] ifte
-                                                23 18 [pop !-] . [--] [++] ifte
-                                           23 18 [pop !-] [--] . [++] ifte
-                                      23 18 [pop !-] [--] [++] . ifte
-                                      23 18 [pop !-] [--] [++] . [nullary not] dipd branch
-                        23 18 [pop !-] [--] [++] [nullary not] . dipd branch
-                                                23 18 [pop !-] . nullary not [--] [++] branch
-                                                23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch
-                                        23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch
-                                        23 18 [pop !-] [stack] . dip infra first not [--] [++] branch
-                                                         23 18 . stack [pop !-] infra first not [--] [++] branch
-                                                 23 18 [18 23] . [pop !-] infra first not [--] [++] branch
-                                        23 18 [18 23] [pop !-] . infra first not [--] [++] branch
-                                                         23 18 . pop !- [18 23] swaack first not [--] [++] branch
-                                                            23 . !- [18 23] swaack first not [--] [++] branch
-                                                            23 . 0 >= [18 23] swaack first not [--] [++] branch
-                                                          23 0 . >= [18 23] swaack first not [--] [++] branch
-                                                          True . [18 23] swaack first not [--] [++] branch
-                                                  True [18 23] . swaack first not [--] [++] branch
-                                                  23 18 [True] . first not [--] [++] branch
-                                                    23 18 True . not [--] [++] branch
-                                                   23 18 False . [--] [++] branch
-                                              23 18 False [--] . [++] branch
-                                         23 18 False [--] [++] . branch
-                                                         23 18 . --
-                                                         23 17 .
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/The_Four_Operations.html b/docs/sphinx_docs/_build/html/notebooks/The_Four_Operations.html deleted file mode 100644 index 0c7896f..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/The_Four_Operations.html +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - - - - The Four Fundamental Operations of Definite Action — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

The Four Fundamental Operations of Definite Action

-

All definite actions (computer program) can be defined by four -fundamental patterns of combination:

-
    -
  1. Sequence

  2. -
  3. Branch

  4. -
  5. Loop

  6. -
  7. Parallel

  8. -
-
-

Sequence

-

Do one thing after another. In joy this is represented by putting two -symbols together, juxtaposition:

-
foo bar
-
-
-

Operations have inputs and outputs. The outputs of foo must be -compatible in “arity”, type, and shape with the inputs of bar.

-
-
-

Branch

-

Do one thing or another.

-
boolean [F] [T] branch
-
-
-   t [F] [T] branch
-----------------------
-          T
-
-
-   f [F] [T] branch
-----------------------
-      F
-
-
-branch == unit cons swap pick i
-
-boolean [F] [T] branch
-boolean [F] [T] unit cons swap pick i
-boolean [F] [[T]] cons swap pick i
-boolean [[F] [T]] swap pick i
-[[F] [T]] boolean pick i
-[F-or-T] i
-
-
-

Given some branch function G:

-
G == [F] [T] branch
-
-
-

Used in a sequence like so:

-
foo G bar
-
-
-

The inputs and outputs of F and T must be compatible with the -outputs for foo and the inputs of bar, respectively.

-
foo F bar
-
-foo T bar
-
-
-
-

ifte

-

Often it will be easier on the programmer to write branching code with -the predicate specified in a quote. The ifte combinator provides -this (T for “then” and E for “else”):

-
[P] [T] [E] ifte
-
-
-

Defined in terms of branch:

-
ifte == [nullary not] dip branch
-
-
-

In this case, P must be compatible with the stack and return a -Boolean value, and T and E both must be compatible with the -preceeding and following functions, as described above for F and -T. (Note that in the current implementation we are depending on -Python for the underlying semantics, so the Boolean value doesn’t have -to be Boolean because Python’s rules for “truthiness” will be used to -evaluate it. I reflect this in the structure of the stack effect comment -of branch, it will only accept Boolean values, and in the definition -of ifte above by including not in the quote, which also has the -effect that the subject quotes are in the proper order for branch.)

-
-
-
-

Loop

-

Do one thing zero or more times.

-
boolean [Q] loop
-
-
-   t [Q] loop
-----------------
-   Q [Q] loop
-
-
-   ... f [Q] loop
---------------------
-   ...
-
-
-

The loop combinator generates a copy of itself in the true branch. -This is the hallmark of recursive defintions. In Thun there is no -equivalent to conventional loops. (There is, however, the x -combinator, defined as x == dup i, which permits recursive -constructs that do not need to be directly self-referential, unlike -loop and genrec.)

-
loop == [] swap [dup dip loop] cons branch
-
-boolean [Q] loop
-boolean [Q] [] swap [dup dip loop] cons branch
-boolean [] [Q] [dup dip loop] cons branch
-boolean [] [[Q] dup dip loop] branch
-
-
-

In action the false branch does nothing while the true branch does:

-
t [] [[Q] dup dip loop] branch
-      [Q] dup dip loop
-      [Q] [Q] dip loop
-      Q [Q] loop
-
-
-

Because loop expects and consumes a Boolean value, the Q -function must be compatible with the previous stack and itself with a -boolean flag for the next iteration:

-
Q == G b
-
-Q [Q] loop
-G b [Q] loop
-G Q [Q] loop
-G G b [Q] loop
-G G Q [Q] loop
-G G G b [Q] loop
-G G G
-
-
-
-

while

-

Keep doing B while some predicate P is true. This is -convenient as the predicate function is made nullary automatically and -the body function can be designed without regard to leaving a Boolean -flag for the next iteration:

-
            [P] [B] while
---------------------------------------
-   [P] nullary [B [P] nullary] loop
-
-
-while == swap [nullary] cons dup dipd concat loop
-
-
-[P] [B] while
-[P] [B] swap [nullary] cons dup dipd concat loop
-[B] [P] [nullary] cons dup dipd concat loop
-[B] [[P] nullary] dup dipd concat loop
-[B] [[P] nullary] [[P] nullary] dipd concat loop
-[P] nullary [B] [[P] nullary] concat loop
-[P] nullary [B [P] nullary] loop
-
-
-
-
-
-

Parallel

-

The parallel operation indicates that two (or more) functions do not -interfere with each other and so can run in parallel. The main -difficulty in this sort of thing is orchestrating the recombining -(“join” or “wait”) of the results of the functions after they finish.

-

The current implementaions and the following definitions are not -actually parallel (yet), but there is no reason they couldn’t be -reimplemented in terms of e.g. Python threads. I am not concerned with -performance of the system just yet, only the elegance of the code it -allows us to write.

-
-

cleave

-

Joy has a few parallel combinators, the main one being cleave:

-
               ... x [A] [B] cleave
----------------------------------------------------------
-   ... [x ...] [A] infra first [x ...] [B] infra first
----------------------------------------------------------
-                   ... a b
-
-
-

The cleave combinator expects a value and two quotes and it executes -each quote in “separate universes” such that neither can affect the -other, then it takes the first item from the stack in each universe and -replaces the value and quotes with their respective results.

-

(I think this corresponds to the “fork” operator, the little -upward-pointed triangle, that takes two functions A :: x -> a and -B :: x -> b and returns a function F :: x -> (a, b), in Conal -Elliott’s “Compiling to Categories” paper, et. al.)

-

Just a thought, if you cleave two jobs and one requires more time to -finish than the other you’d like to be able to assign resources -accordingly so that they both finish at the same time.

-
-
-

“Apply” Functions

-

There are also app2 and app3 which run a single quote on more -than one value:

-
                ... y x [Q] app2
----------------------------------------------------------
-   ... [y ...] [Q] infra first [x ...] [Q] infra first
-
-
-       ... z y x [Q] app3
----------------------------------
-   ... [z ...] [Q] infra first
-       [y ...] [Q] infra first
-       [x ...] [Q] infra first
-
-
-

Because the quoted program can be i we can define cleave in -terms of app2:

-
cleave == [i] app2 [popd] dip
-
-
-

(I’m not sure why cleave was specified to take that value, I may -make a combinator that does the same thing but without expecting a -value.)

-
clv == [i] app2
-
-   [A] [B] clv
-------------------
-     a b
-
-
-
-
-

map

-

The common map function in Joy should also be though of as a -parallel operator:

-
[a b c ...] [Q] map
-
-
-

There is no reason why the implementation of map couldn’t distribute -the Q function over e.g. a pool of worker CPUs.

-
-
-

pam

-

One of my favorite combinators, the pam combinator is just:

-
pam == [i] map
-
-
-

This can be used to run any number of programs separately on the current -stack and combine their (first) outputs in a result list.

-
   [[A] [B] [C] ...] [i] map
--------------------------------
-   [ a   b   c  ...]
-
-
-
-
-

Handling Other Kinds of Join

-

The cleave operators and others all have pretty brutal join -semantics: everything works and we always wait for every -sub-computation. We can imagine a few different potentially useful -patterns of “joining” results from parallel combinators.

-
-

first-to-finish

-

Thinking about variations of pam there could be one that only -returns the first result of the first-to-finish sub-program, or the -stack could be replaced by its output stack.

-

The other sub-programs would be cancelled.

-
-
-

“Fulminators”

-

Also known as “Futures” or “Promises” (by everybody else. “Fulminators” -is what I was going to call them when I was thinking about implementing -them in Thun.)

-

The runtime could be amended to permit “thunks” representing the results -of in-progress computations to be left on the stack and picked up by -subsequent functions. These would themselves be able to leave behind -more “thunks”, the values of which depend on the eventual resolution of -the values of the previous thunks.

-

In this way you can create “chains” (and more complex shapes) out of -normal-looking code that consist of a kind of call-graph interspersed -with “asyncronous” … events?

-

In any case, until I can find a rigorous theory that shows that this -sort of thing works perfectly in Joy code I’m not going to worry about -it. (And I think the Categories can deal with it anyhow? Incremental -evaluation, yeah?)

-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Treestep.html b/docs/sphinx_docs/_build/html/notebooks/Treestep.html deleted file mode 100644 index f5d8d63..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Treestep.html +++ /dev/null @@ -1,581 +0,0 @@ - - - - - - - - - Treating Trees II: treestep — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Treating Trees II: treestep

-

Let’s consider a tree structure, similar to one described “Why -functional programming matters” by John -Hughes, -that consists of a node value followed by zero or more child trees. (The -asterisk is meant to indicate the Kleene -star.)

-
tree = [] | [node tree*]
-
-
-

In the spirit of step we are going to define a combinator -treestep which expects a tree and three additional items: a -base-case function [B], and two quoted programs [N] and [C].

-
tree [B] [N] [C] treestep
-
-
-

If the current tree node is empty then just execute B:

-
   [] [B] [N] [C] treestep
----------------------------
-   []  B
-
-
-

Otherwise, evaluate N on the node value, map the whole function -(abbreviated here as K) over the child trees recursively, and then -combine the result with C.

-
   [node tree*] [B] [N] [C] treestep
---------------------------------------- w/ K == [B] [N] [C] treestep
-       node N [tree*] [K] map C
-
-
-

(Later on we’ll experiment with making map part of C so you can -use other combinators.)

-
-

Derive the recursive function.

-

We can begin to derive it by finding the ifte stage that genrec -will produce.

-
K == [not] [B] [R0]   [R1] genrec
-  == [not] [B] [R0 [K] R1] ifte
-
-
-

So we just have to derive J:

-
J == R0 [K] R1
-
-
-

The behavior of J is to accept a (non-empty) tree node and arrive at -the desired outcome.

-
       [node tree*] J
-------------------------------
-   node N [tree*] [K] map C
-
-
-

So J will have some form like:

-
J == ... [N] ... [K] ... [C] ...
-
-
-

Let’s dive in. First, unquote the node and dip N.

-
[node tree*] uncons [N] dip
-node [tree*]        [N] dip
-node N [tree*]
-
-
-

Next, map K over the child trees and combine with C.

-
node N [tree*] [K] map C
-node N [tree*] [K] map C
-node N [K.tree*]       C
-
-
-

So:

-
J == uncons [N] dip [K] map C
-
-
-

Plug it in and convert to genrec:

-
K == [not] [B] [J                       ] ifte
-  == [not] [B] [uncons [N] dip [K] map C] ifte
-  == [not] [B] [uncons [N] dip]   [map C] genrec
-
-
-
-
-

Extract the givens to parameterize the program.

-

Working backwards:

-
[not] [B]          [uncons [N] dip]                  [map C] genrec
-[B] [not] swap     [uncons [N] dip]                  [map C] genrec
-[B]                [uncons [N] dip] [[not] swap] dip [map C] genrec
-                                    ^^^^^^^^^^^^^^^^
-[B] [[N] dip]      [uncons] swoncat [[not] swap] dip [map C] genrec
-[B] [N] [dip] cons [uncons] swoncat [[not] swap] dip [map C] genrec
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-
-

Extract a couple of auxiliary definitions:

-
TS.0 == [[not] swap] dip
-TS.1 == [dip] cons [uncons] swoncat
-
-
-
[B] [N] TS.1 TS.0 [map C]                         genrec
-[B] [N]           [map C]         [TS.1 TS.0] dip genrec
-[B] [N] [C]         [map] swoncat [TS.1 TS.0] dip genrec
-
-
-

The givens are all to the left so we have our definition.

-
-

(alternate) Extract the givens to parameterize the program.

-

Working backwards:

-
[not] [B]           [uncons [N] dip]            [map C] genrec
-[not] [B] [N]       [dip] cons [uncons] swoncat [map C] genrec
-[B] [N] [not] roll> [dip] cons [uncons] swoncat [map C] genrec
-        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-
-
-
-
-

Define treestep

-
from notebook_preamble import D, J, V, define, DefinitionWrapper
-
-
-
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
-
-''', D)
-
-
-
-
-

Examples

-

Consider trees, the nodes of which are integers. We can find the sum of -all nodes in a tree with this function:

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

Running this function on an empty tree value gives zero:

-
   [] [pop 0] [] [sum +] treestep
-------------------------------------
-           0
-
-
-
J('[] sumtree')  # Empty tree.
-
-
-
0
-
-
-

Running it on a non-empty node:

-
[n tree*]  [pop 0] [] [sum +] treestep
-n [tree*] [[pop 0] [] [sum +] treestep] map sum +
-n [ ... ]                                   sum +
-n m                                             +
-n+m
-
-
-
J('[23] sumtree')  # No child trees.
-
-
-
23
-
-
-
J('[23 []] sumtree')  # Child tree, empty.
-
-
-
23
-
-
-
J('[23 [2 [4]] [3]] sumtree')  # Non-empty child trees.
-
-
-
32
-
-
-
J('[23 [2 [8] [9]] [3] [4 []]] sumtree')  # Etc...
-
-
-
49
-
-
-
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.
-
-
-
[23 [23 [23] [23]] [23] [23 []]]
-
-
-
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')
-
-
-
6
-
-
-
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.
-
-
-
3
-
-
-
-
-

Redefining the Ordered Binary Tree in terms of treestep.

-
Tree = [] | [[key value] left right]
-
-
-

What kind of functions can we write for this with our treestep?

-

The pattern for processing a non-empty node is:

-
node N [tree*] [K] map C
-
-
-

Plugging in our BTree structure:

-
[key value] N [left right] [K] map C
-
-
-
-

Traversal

-
[key value] first [left right] [K] map i
-key [value]       [left right] [K] map i
-key               [left right] [K] map i
-key               [lkey rkey ]         i
-key                lkey rkey
-
-
-

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')
-
-
-
3 'B' 'B'
-
-
-

Doesn’t work because map extracts the first item of whatever its -mapped function produces. We have to return a list, rather than -depositing our results directly on the stack.

-
[key value] N     [left right] [K] map C
-
-[key value] first [left right] [K] map flatten cons
-key               [left right] [K] map flatten cons
-key               [[lk] [rk] ]         flatten cons
-key               [ lk   rk  ]                 cons
-                  [key  lk   rk  ]
-
-
-

So:

-
[] [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]
-
-
-

There we go.

-
-
-

In-order traversal

-

From here:

-
key [[lk] [rk]] C
-key [[lk] [rk]] i
-key  [lk] [rk] roll<
-[lk] [rk] key swons concat
-[lk] [key rk]       concat
-[lk   key rk]
-
-
-

So:

-
[] [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')
-
-
-
[2 3 4 5 6 7 8 9]
-
-
-
-
-
-

With treegrind?

-

The treegrind function doesn’t include the map combinator, so -the [C] function must arrange to use some combinator on the quoted -recursive copy [K]. With this function, the pattern for processing a -non-empty node is:

-
node N [tree*] [K] C
-
-
-

Plugging in our BTree structure:

-
[key value] N [left right] [K] C
-
-
-
J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind')
-
-
-
['key' 'value'] 'N' [['left'] ['right']] [[not] ['B'] [uncons ['N'] dip] ['C'] genrec] 'C'
-
-
-
-
-

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')
-
-
-
[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')
-
-
-
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')
-
-
-
[[103 0] [[102 0] [] []] [[109 0] [[105 0] [[104 0] [] []] [[108 0] [[106 0] [] [[107 0] [] []]] []]] []]]
-
-
-
-
-

Do we have the flexibility to reimplement Tree-get?

-

I think we do:

-
[B] [N] [C] treegrind
-
-
-

We’ll start by saying that the base-case (the key is not in the tree) is -user defined, and the per-node function is just the query key literal:

-
[B] [query_key] [C] treegrind
-
-
-

This means we just have to define C from:

-
[key value] query_key [left right] [K] C
-
-
-

Let’s try cmp:

-
C == P [T>] [E] [T<] cmp
-
-[key value] query_key [left right] [K] P [T>] [E] [T<] cmp
-
-
-
-

The predicate P

-

Seems pretty easy (we must preserve the value in case the keys are -equal):

-
[key value] query_key [left right] [K] P
-[key value] query_key [left right] [K] roll<
-[key value] [left right] [K] query_key       [roll< uncons swap] dip
-
-[key value] [left right] [K] roll< uncons swap query_key
-[left right] [K] [key value]       uncons swap query_key
-[left right] [K] key [value]              swap query_key
-[left right] [K] [value] key                   query_key
-
-P == roll< [roll< uncons swap] dip
-
-
-

(Possibly with a swap at the end? Or just swap T< and T>.)

-

So now:

-
[left right] [K] [value] key query_key [T>] [E] [T<] cmp
-
-
-

Becomes one of these three:

-
[left right] [K] [value] T>
-[left right] [K] [value] E
-[left right] [K] [value] T<
-
-
-
-
-

E

-

Easy.

-
E == roll> popop first
-
-
-
-
-

T< and T>

-
T< == pop [first] dip i
-T> == pop [second] dip i
-
-
-
-
-
-

Putting it together

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

To me, that seems simpler than the genrec version.

-
DefinitionWrapper.add_definitions('''
-
-    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
-
-''', D)
-
-
-
J('''\
-
-[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
-
-[] [5] Tree-get
-
-''')
-
-
-
15
-
-
-
J('''\
-
-[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]
-
-[pop "nope"] [25] Tree-get
-
-''')
-
-
-
'nope'
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/TypeChecking.html b/docs/sphinx_docs/_build/html/notebooks/TypeChecking.html deleted file mode 100644 index 09ebb68..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/TypeChecking.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - - - - Type Checking — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Type Checking

-
import logging, sys
-
-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,
-)
-
-
-
D = FUNCTIONS.copy()
-del D['product']
-globals().update(D)
-
-
-
-

An Example

-
fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0]
-
-
-
25 (--) ∘ pop swap rolldown rrest ccons
-28 (a1 --) ∘ swap rolldown rrest ccons
-31 (a3 a2 a1 -- a2 a3) ∘ rolldown rrest ccons
-34 (a4 a3 a2 a1 -- a2 a3 a4) ∘ rrest ccons
-37 ([a4 a5 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ ccons
-40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘
-
-
-
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
-
-
-
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
-
-
-
{a1: 0, a2: 1, a3: 2, a4: 3, a5: 4, s2: (), s1: ()}
-
-
-
g = reify(u, (fi, fo))
-print doc_from_stack_effect(*g)
-
-
-
(... [3 4 ] 2 1 0 -- ... [1 2 ])
-
-
-
-
-

Unification Works “in Reverse”

-
e = text_to_expression('[2 3]')
-
-
-
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)
-
-
-
(... [a4 a5 ] 3 2 a1 -- ... [2 3 ])
-
-
-
-
-

Failing a Check

-
fi, fo = infer(dup, mul)[0]
-
-
-
25 (--) ∘ dup mul
-28 (a1 -- a1 a1) ∘ mul
-31 (f1 -- f2) ∘
-31 (i1 -- i2) ∘
-
-
-
e = text_to_expression('"two"')
-print stack_to_string(e)
-
-
-
'two'
-
-
-
try:
-    unify(e, fi)
-except JoyTypeError, err:
-    print err
-
-
-
Cannot unify 'two' and f1.
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Types.html b/docs/sphinx_docs/_build/html/notebooks/Types.html deleted file mode 100644 index 8a5b149..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Types.html +++ /dev/null @@ -1,2472 +0,0 @@ - - - - - - - - - The Blissful Elegance of Typing Joy — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

The Blissful Elegance of Typing Joy

-

This notebook presents a simple type inferencer for Joy code. It can -infer the stack effect of most Joy expressions. It’s built largely by -means of existing ideas and research. (A great overview of the existing -knowledge is a talk “Type Inference in Stack-Based Programming -Languages” -given by Rob Kleffner on or about 2017-03-10 as part of a course on the -history of programming languages.)

-

The notebook starts with a simple inferencer based on the work of Jaanus -Pöial which we then progressively elaborate to cover more Joy semantics. -Along the way we write a simple “compiler” that emits Python code for -what I like to call Yin functions. (Yin functions are those that only -rearrange values in stacks, as opposed to Yang functions that actually -work on the values themselves.)

-
-

Part I: Pöial’s Rules

-

“Typing Tools for Typeless Stack Languages” by Jaanus -Pöial

-
@INPROCEEDINGS{Pöial06typingtools,
-    author = {Jaanus Pöial},
-    title = {Typing tools for typeless stack languages},
-    booktitle = {In 23rd Euro-Forth Conference},
-    year = {2006},
-    pages = {40--46}
-}
-
-
-
-

First Rule

-

This rule deals with functions (and literals) that put items on the -stack (-- d):

-
   (a -- b)∘(-- d)
----------------------
-     (a -- b d)
-
-
-
-
-

Second Rule

-

This rule deals with functions that consume items from the stack -(a --):

-
   (a --)∘(c -- d)
----------------------
-     (c a -- d)
-
-
-
-
-

Third Rule

-

The third rule is actually two rules. These two rules deal with -composing functions when the second one will consume one of items the -first one produces. The two types must be -unified -or a type conflict declared.

-
   (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)
--------------------------------
-   (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
-                                         ^
-
-   (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)
--------------------------------
-   (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
-
-
-

Let’s work through some examples by hand to develop an intuition for the -algorithm.

-

There’s a function in one of the other notebooks.

-
F == pop swap roll< rest rest cons cons
-
-
-

It’s all “stack chatter” and list manipulation so we should be able to -deduce its type.

-
-
-

Stack Effect Comments

-

Joy function types will be represented by Forth-style stack effect -comments. I’m going to use numbers instead of names to keep track of the -stack arguments. (A little bit like De Bruijn -index, at least it -reminds me of them):

-
pop (1 --)
-
-swap (1 2 -- 2 1)
-
-roll< (1 2 3 -- 2 3 1)
-
-
-

These commands alter the stack but don’t “look at” the values so these -numbers represent an “Any type”.

-
-
-

pop swap

-
(1 --) (1 2 -- 2 1)
-
-
-

Here we encounter a complication. The argument numbers need to be made -unique among both sides. For this let’s change pop to use 0:

-
(0 --) (1 2 -- 2 1)
-
-
-

Following the second rule:

-
(1 2 0 -- 2 1)
-
-
-
-
-

pop∘swap roll<

-
(1 2 0 -- 2 1) (1 2 3 -- 2 3 1)
-
-
-

Let’s re-label them:

-
(1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
-
-
-

Now we follow the rules.

-

We must unify 1a and 3b, and 2a and 2b, replacing the -terms in the forms:

-
(1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b)
-                                            w/  {1a: 3b}
-(3b 2a 0a -- 2a   ) (1b 2b    -- 2b 3b 1b)
-                                            w/  {2a: 2b}
-(3b 2b 0a --      ) (1b       -- 2b 3b 1b)
-
-
-

Here we must apply the second rule:

-
   (3b 2b 0a --) (1b -- 2b 3b 1b)
------------------------------------
-     (1b 3b 2b 0a -- 2b 3b 1b)
-
-
-

Now we de-label the type, uh, labels:

-
(1b 3b 2b 0a -- 2b 3b 1b)
-
-w/ {
-    1b: 1,
-    3b: 2,
-    2b: 3,
-    0a: 0,
-    }
-
-(1 2 3 0 -- 3 2 1)
-
-
-

And now we have the stack effect comment for pop∘swap∘roll<.

-
-
-

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

However, internally this function would still be allocating tuples -(stack cells) and doing other unnecesssary work.

-

Looking ahead for a moment, from the stack effect comment:

-
(1 2 3 0 -- 3 2 1)
-
-
-

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

This eliminates the internal work of the first version. Because this -function only rearranges the stack and doesn’t do any actual processing -on the stack items themselves all the information needed to implement it -is in the stack effect comment.

-
-
-

Functions on Stacks

-

These are slightly tricky.

-
rest ( [1 ...] -- [...] )
-
-cons ( 1 [...] -- [1 ...] )
-
-
-
-
-

pop∘swap∘roll< rest

-
(1 2 3 0 -- 3 2 1) ([1 ...] -- [...])
-
-
-

Re-label (instead of adding left and right tags I’m just taking the next -available index number for the right-side stack effect comment):

-
(1 2 3 0 -- 3 2 1) ([4 ...] -- [...])
-
-
-

Unify and update:

-
(1       2 3 0 -- 3 2 1) ([4 ...] -- [...])
-                                             w/ {1: [4 ...]}
-([4 ...] 2 3 0 -- 3 2  ) (        -- [...])
-
-
-

Apply the first rule:

-
   ([4 ...] 2 3 0 -- 3 2) (-- [...])
----------------------------------------
-     ([4 ...] 2 3 0 -- 3 2 [...])
-
-
-

And there we are.

-
-
-

pop∘swap∘roll<∘rest rest

-

Let’s do it again.

-
([4 ...] 2 3 0 -- 3 2 [...]) ([1 ...] -- [...])
-
-
-

Re-label (the tails of the lists on each side each get their own label):

-
([4 .0.] 2 3 0 -- 3 2 [.0.]) ([5 .1.] -- [.1.])
-
-
-

Unify and update (note the opening square brackets have been omited in -the substitution dict, this is deliberate and I’ll explain below):

-
([4 .0.]   2 3 0 -- 3 2 [.0.]  ) ([5 .1.] -- [.1.])
-                                                    w/ { .0.] : 5 .1.] }
-([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
-
-
-

How do we find .0.] in [4 .0.] and replace it with 5 .1.] -getting the result [4 5 .1.]? This might seem hard, but because the -underlying structure of the Joy list is a cons-list in Python it’s -actually pretty easy. I’ll explain below.

-

Next we unify and find our two terms are the same already: [5 .1.]:

-
([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.])
-
-
-

Giving us:

-
([4 5 .1.] 2 3 0 -- 3 2) (-- [.1.])
-
-
-

From here we apply the first rule and get:

-
([4 5 .1.] 2 3 0 -- 3 2 [.1.])
-
-
-

Cleaning up the labels:

-
([4 5 ...] 2 3 1 -- 3 2 [...])
-
-
-

This is the stack effect of pop∘swap∘roll<∘rest∘rest.

-
-
-

pop∘swap∘roll<∘rest∘rest cons

-
([4 5 ...] 2 3 1 -- 3 2 [...]) (1 [...] -- [1 ...])
-
-
-

Re-label:

-
([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
-
-
-

Unify:

-
([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.])
-                                                     w/ { .1.] : .2.] }
-([4 5 .2.] 2 3 1 -- 3 2      ) (6       -- [6 .2.])
-                                                     w/ {2: 6}
-([4 5 .2.] 6 3 1 -- 3        ) (        -- [6 .2.])
-
-
-

First rule:

-
([4 5 .2.] 6 3 1 -- 3 [6 .2.])
-
-
-

Re-label:

-
([4 5 ...] 2 3 1 -- 3 [2 ...])
-
-
-

Done.

-
-
-

pop∘swap∘roll<∘rest∘rest∘cons cons

-

One more time.

-
([4 5 ...] 2 3 1 -- 3 [2 ...]) (1 [...] -- [1 ...])
-
-
-

Re-label:

-
([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.])
-
-
-

Unify:

-
([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.]  )
-                                                       w/ { .2.] : 2 .1.] }
-([4 5 .1.] 2 3 1 -- 3        ) (6       -- [6 2 .1.])
-                                                       w/ {3: 6}
-([4 5 .1.] 2 6 1 --          ) (        -- [6 2 .1.])
-
-
-

First or second rule:

-
([4 5 .1.] 2 6 1 -- [6 2 .1.])
-
-
-

Clean up the labels:

-
([4 5 ...] 2 3 1 -- [3 2 ...])
-
-
-

And there you have it, the stack effect for -pop∘swap∘roll<∘rest∘rest∘cons∘cons.

-
([4 5 ...] 2 3 1 -- [3 2 ...])
-
-
-

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

Part II: Implementation

-
-

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)
-
-pop = (1,), ()
-
-swap = (1, 2), (2, 1)
-
-
-
-
-

compose()

-
def compose(f, g):
-
-    (f_in, f_out), (g_in, g_out) = f, g
-
-    # First rule.
-    #
-    #       (a -- b) (-- d)
-    #    ---------------------
-    #         (a -- b d)
-
-    if not g_in:
-
-        fg_in, fg_out = f_in, f_out + g_out
-
-    # Second rule.
-    #
-    #       (a --) (c -- d)
-    #    ---------------------
-    #         (c a -- d)
-
-    elif not f_out:
-
-        fg_in, fg_out = g_in + f_in, g_out
-
-    else: # Unify, update, recur.
-
-        fo, gi = f_out[-1], g_in[-1]
-
-        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))
-
-        f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out)
-
-        if s: f_g = update(s, f_g)
-
-        fg_in, fg_out = compose(*f_g)
-
-    return fg_in, fg_out
-
-
-
-
-

unify()

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

relabel()

-
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)
-
-relabel(pop, swap)
-
-
-
(((1,), ()), ((1001, 1002), (1002, 1001)))
-
-
-
-
-

delabel()

-
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
-
-delabel(relabel(pop, swap))
-
-
-
(((0,), ()), ((1, 2), (2, 1)))
-
-
-
-
-

C()

-

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

Let’s try it out.

-
C(pop, swap)
-
-
-
((1, 2, 0), (2, 1))
-
-
-
C(C(pop, swap), roll_dn)
-
-
-
((3, 1, 2, 0), (2, 1, 3))
-
-
-
C(swap, roll_dn)
-
-
-
((2, 0, 1), (1, 0, 2))
-
-
-
C(pop, C(swap, roll_dn))
-
-
-
((3, 1, 2, 0), (2, 1, 3))
-
-
-
poswrd = reduce(C, (pop, swap, roll_dn))
-poswrd
-
-
-
((3, 1, 2, 0), (2, 1, 3))
-
-
-
-
-

Stack Functions

-

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,)
-
-cons = (1, 2), ((1, 2),)
-
-
-
C(poswrd, rest)
-
-
-
(((3, 4), 1, 2, 0), (2, 1, 4))
-
-
-

Compare this to the stack effect comment we wrote above:

-
((  (3, 4), 1, 2, 0 ), ( 2, 1,   4  ))
-(   [4 ...] 2  3  0  --  3  2  [...])
-
-
-

The translation table, if you will, would be:

-
{
-3: 4,
-4: ...],
-1: 2,
-2: 3,
-0: 0,
-}
-
-
-
F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons))
-
-F
-
-
-
(((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),))
-
-
-

Compare with the stack effect comment and you can see it works fine:

-
([4 5 ...] 2 3 1 -- [3 2 ...])
-  3 4  5   1 2 0     2 1  5
-
-
-
-
-

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)
-
-
-
try:
-    C(cons, uncons)
-except Exception, e:
-    print e
-
-
-
Cannot unify (1, 2) and (1001, 1002).
-
-
-
-

unify() version 2

-

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)
-
-    if isinstance(u, int):
-        s[u] = v
-
-    elif isinstance(v, int):
-        s[v] = u
-
-    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.
-
-        (a, b), (c, d) = u, v
-        s = unify(a, c, s)
-        if s != False:
-            s = unify(b, d, s)
-    else:
-        s = False
-
-    return s
-
-
-
C(cons, uncons)
-
-
-
((0, 1), (0, 1))
-
-
-
-
-
-
-

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

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

-
F[0]
-
-
-
((3, (4, 5)), 1, 2, 0)
-
-
-

The stack-de-structuring tuple has nearly the same form as our input -stack effect comment tuple, just in the reverse order:

-
(_, (d, (c, ((a, (b, S0)), stack))))
-
-
-

Remove the punctuation:

-
_   d   c   (a, (b, S0))
-
-
-

Reverse the order and compare:

-
 (a, (b, S0))   c   d   _
-((3, (4, 5 )),  1,  2,  0)
-
-
-

Eh?

-

And the return tuple

-
F[1]
-
-
-
((2, (1, 5)),)
-
-
-

is similar to the output stack effect comment tuple:

-
((d, (c, S0)), stack)
-((2, (1, 5 )),      )
-
-
-

This should make it pretty easy to write a Python function that accepts -the stack effect comment tuples and returns a new Python function -(either as a string of code or a function object ready to use) that -performs the semantics of that Joy function (described by the stack -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
-
-
-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)
-
-
-
-
-

doc_from_stack_effect()

-

As a convenience I’ve implemented a function to convert the Python stack -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)
-
-
-
-
-

compile_()

-

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

Here it is in action:

-
source = compile_('F', F)
-
-print source
-
-
-
def F(stack):
-    """([3 4 .5.] 1 2 0 -- [2 1 .5.])"""
-    (a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack
-    return ((a4, (a3, a2)), stack)
-
-
-

Compare:

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

Next steps:

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

Let’s try it out:

-
from notebook_preamble import D, J, V
-from joy.library import SimpleFunctionWrapper
-
-
-
D['F'] = SimpleFunctionWrapper(L['F'])
-
-
-
J('[4 5 ...] 2 3 1 F')
-
-
-
[3 2 ...]
-
-
-

With this, we have a partial Joy compiler that works on the subset of -Joy functions that manipulate stacks (both what I call “stack chatter” -and the ones that manipulate stacks on the stack.)

-

I’m probably going to modify the definition wrapper code to detect -definitions that can be compiled by this partial compiler and do it -automatically. It might be a reasonable idea to detect sequences of -compilable functions in definitions that have uncompilable functions in -them and just compile those. However, if your library is well-factored -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():
-
-    rolldown = (1, 2, 3), (2, 3, 1)
-
-    rollup = (1, 2, 3), (3, 1, 2)
-
-    pop = (1,), ()
-
-    swap = (1, 2), (2, 1)
-
-    rest = ((1, 2),), (2,)
-
-    rrest = C(rest, rest)
-
-    cons = (1, 2), ((1, 2),)
-
-    uncons = ((1, 2),), (1, 2)
-
-    swons = C(swap, cons)
-
-    return locals()
-
-
-
for name, stack_effect_comment in sorted(defs().items()):
-    print
-    print compile_(name, stack_effect_comment)
-    print
-
-
-
def cons(stack):
-    """(1 2 -- [1 .2.])"""
-    (a1, (a0, stack)) = stack
-    return ((a0, a1), stack)
-
-
-def pop(stack):
-    """(1 --)"""
-    (a0, stack) = stack
-    return stack
-
-
-def rest(stack):
-    """([1 .2.] -- 2)"""
-    ((a0, a1), stack) = stack
-    return (a1, stack)
-
-
-def rolldown(stack):
-    """(1 2 3 -- 2 3 1)"""
-    (a2, (a1, (a0, stack))) = stack
-    return (a0, (a2, (a1, stack)))
-
-
-def rollup(stack):
-    """(1 2 3 -- 3 1 2)"""
-    (a2, (a1, (a0, stack))) = stack
-    return (a1, (a0, (a2, stack)))
-
-
-def rrest(stack):
-    """([0 1 .2.] -- 2)"""
-    ((a0, (a1, a2)), stack) = stack
-    return (a2, stack)
-
-
-def swap(stack):
-    """(1 2 -- 2 1)"""
-    (a1, (a0, stack)) = stack
-    return (a0, (a1, stack))
-
-
-def swons(stack):
-    """(0 1 -- [1 .0.])"""
-    (a1, (a0, stack)) = stack
-    return ((a1, a0), stack)
-
-
-def uncons(stack):
-    """([1 .2.] -- 1 2)"""
-    ((a0, a1), stack) = stack
-    return (a1, (a0, stack))
-
-
-
-
-
-

Part IV: Types and Subtypes of Arguments

-

So far we have dealt with types of functions, those dealing with simple -stack manipulation. Let’s extend our machinery to deal with types of -arguments.

-
-

“Number” Type

-

Consider the definition of sqr:

-
sqr == dup mul
-
-
-

The dup function accepts one anything and returns two of that:

-
dup (1 -- 1 1)
-
-
-

And mul accepts two “numbers” (we’re ignoring ints vs. floats -vs. complex, etc., for now) and returns just one:

-
mul (n n -- n)
-
-
-

So we’re composing:

-
(1 -- 1 1)∘(n n -- n)
-
-
-

The rules say we unify 1 with n:

-
   (1 -- 1 1)∘(n n -- n)
----------------------------  w/  {1: n}
-   (1 -- 1  )∘(n   -- n)
-
-
-

This involves detecting that “Any type” arguments can accept “numbers”. -If we were composing these functions the other way round this is still -the case:

-
   (n n -- n)∘(1 -- 1 1)
----------------------------  w/  {1: n}
-   (n n --  )∘(  -- n n)
-
-
-

The important thing here is that the mapping is going the same way in -both cases, from the “any” integer to the number

-
-
-

Distinguishing Numbers

-

We should also mind that the number that mul produces is not -(necessarily) the same as either of its inputs, which are not -(necessarily) the same as each other:

-
mul (n2 n1 -- n3)
-
-
-   (1  -- 1  1)∘(n2 n1 -- n3)
---------------------------------  w/  {1: n2}
-   (n2 -- n2  )∘(n2    -- n3)
-
-
-   (n2 n1 -- n3)∘(1 -- 1  1 )
---------------------------------  w/  {1: n3}
-   (n2 n1 --   )∘(  -- n3 n3)
-
-
-
-
-

Distinguishing Types

-

So we need separate domains of “any” numbers and “number” numbers, and -we need to be able to ask the order of these domains. Now the notes on -the right side of rule three make more sense, eh?

-
   (a -- b t[i])∘(c u[j] -- d)   t <= u (t is subtype of u)
--------------------------------
-   (a -- b     )∘(c      -- d)   t[i] == t[k] == u[j]
-                                         ^
-
-   (a -- b t[i])∘(c u[j] -- d)   u <= t (u is subtype of t)
--------------------------------
-   (a -- b     )∘(c      -- d)   t[i] == u[k] == u[j]
-
-
-

The indices i, k, and j are the number part of our labels -and t and u are the domains.

-

By creative use of Python’s “double underscore” methods we can define a -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):
-
-    prefix = 'a'
-
-    def __init__(self, number):
-        self.number = 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 __ge__(self, other):
-        return issubclass(other.__class__, self.__class__)
-
-    def __add__(self, other):
-        return self.__class__(self.number + other)
-    __radd__ = __add__
-
-    def __hash__(self):
-        return hash(repr(self))
-
-
-class NumberJoyType(AnyJoyType): prefix = 'n'
-class FloatJoyType(NumberJoyType): prefix = 'f'
-class IntJoyType(FloatJoyType): prefix = 'i'
-
-
-class StackJoyType(AnyJoyType):
-    prefix = 's'
-
-
-_R = range(10)
-A = map(AnyJoyType, _R)
-N = map(NumberJoyType, _R)
-S = map(StackJoyType, _R)
-
-
-

Mess with it a little:

-
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
-
-
-
a0 >= n0 -> True
-a0 >= s0 -> True
-n0 >= a0 -> False
-n0 >= s0 -> False
-s0 >= a0 -> False
-s0 >= n0 -> False
-
-
-

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
-
-
-
a0 >= n0 -> True
-a0 >= f0 -> True
-a0 >= i0 -> True
-n0 >= a0 -> False
-n0 >= f0 -> True
-n0 >= i0 -> True
-f0 >= a0 -> False
-f0 >= n0 -> False
-f0 >= i0 -> True
-i0 >= a0 -> False
-i0 >= n0 -> False
-i0 >= f0 -> False
-
-
-
-
-

Typing sqr

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

Modifying the Inferencer

-

Re-labeling still works fine:

-
foo = relabel(dup, mul)
-
-foo
-
-
-
(((a1,), (a1, a1)), ((n1001, n1002), (n1003,)))
-
-
-
-

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
-
-
-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
-
-    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)
-
-
-
delabel(foo)
-
-
-
(((a1,), (a1, a1)), ((n1, n2), (n3,)))
-
-
-
-
-

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}
-
-
-

Rewrite the stack effect comments:

-
def defs():
-
-    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])
-
-    pop = (A[1],), ()
-
-    popop = (A[2], A[1],), ()
-
-    popd = (A[2], A[1],), (A[1],)
-
-    popdd = (A[3], A[2], A[1],), (A[2], A[1],)
-
-    swap = (A[1], A[2]), (A[2], A[1])
-
-    rest = ((A[1], S[1]),), (S[1],)
-
-    rrest = C(rest, rest)
-
-    cons = (A[1], S[1]), ((A[1], S[1]),)
-
-    ccons = C(cons, cons)
-
-    uncons = ((A[1], S[1]),), (A[1], S[1])
-
-    swons = C(swap, cons)
-
-    dup = (A[1],), (A[1], A[1])
-
-    dupd = (A[2], A[1]), (A[2], A[2], A[1])
-
-    mul = (N[1], N[2]), (N[3],)
-
-    sqrt = C(dup, mul)
-
-    first = ((A[1], S[1]),), (A[1],)
-
-    second = C(rest, first)
-
-    third = C(rest, second)
-
-    tuck = (A[2], A[1]), (A[1], A[2], A[1])
-
-    over = (A[2], A[1]), (A[2], A[1], A[2])
-
-    succ = pred = (N[1],), (N[2],)
-
-    divmod_ = pm = (N[2], N[1]), (N[4], N[3])
-
-    return locals()
-
-
-
DEFS = defs()
-
-
-
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.])
-cons = (a1 [.1.] -- [a1 .1.])
-divmod_ = (n2 n1 -- n4 n3)
-dup = (a1 -- a1 a1)
-dupd = (a2 a1 -- a2 a2 a1)
-first = ([a1 .1.] -- a1)
-mul = (n1 n2 -- n3)
-over = (a2 a1 -- a2 a1 a2)
-pm = (n2 n1 -- n4 n3)
-pop = (a1 --)
-popd = (a2 a1 -- a1)
-popdd = (a3 a2 a1 -- a2 a1)
-popop = (a2 a1 --)
-pred = (n1 -- n2)
-rest = ([a1 .1.] -- [.1.])
-rolldown = (a1 a2 a3 -- a2 a3 a1)
-rollup = (a1 a2 a3 -- a3 a1 a2)
-rrest = ([a1 a2 .1.] -- [.1.])
-second = ([a1 a2 .1.] -- a2)
-sqrt = (n1 -- n2)
-succ = (n1 -- n2)
-swap = (a1 a2 -- a2 a1)
-swons = ([.1.] a1 -- [a1 .1.])
-third = ([a1 a2 a3 .1.] -- a3)
-tuck = (a2 a1 -- a1 a2 a1)
-uncons = ([a1 .1.] -- a1 [.1.])
-
-
-
globals().update(DEFS)
-
-
-
-
-

Compose dup and mul

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

Revisit the F function, works fine.

-
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)
-
-
-
([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.])
-
-
-

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))
-
-
-
# e.g. [swap] dip
-neato(rollup, swap, rolldown)
-
-
-
(a1 a2 a3 -- a2 a1 a3)
-
-
-
# 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)
-
-
-
(a1 a2 a3 -- a3 a2 a1)
-
-
-
-
-

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)
-
-
-
print compile_('F', F)
-
-
-
def F(stack):
-    """([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.])"""
-    (a5, (a4, (a3, ((a1, (a2, s1)), stack)))) = stack
-    return ((a4, (a3, s1)), stack)
-
-
-

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))
-
-
-
def sqr(stack):
-    """(n1 -- n2)"""
-    (n1, stack) = stack
-    return (n2, stack)
-
-
-

(Eventually I should come back around to this becuase it’s not tooo -difficult to exend this code to be able to compile e.g. -n2 = mul(n1, n1) for mul with the right variable names and -insert it in the right place. It requires a little more support from the -library functions, in that we need to know to call mul() the Python -function for mul the Joy function, but since most of the math -functions (at least) are already wrappers it should be straightforward.)

-
-
-

compilable()

-

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
-
-
-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)
-
-
-
ccons = (a1 a2 [.1.] -- [a1 a2 .1.])
-cons = (a1 [.1.] -- [a1 .1.])
-dup = (a1 -- a1 a1)
-dupd = (a2 a1 -- a2 a2 a1)
-first = ([a1 .1.] -- a1)
-over = (a2 a1 -- a2 a1 a2)
-pop = (a1 --)
-popd = (a2 a1 -- a1)
-popdd = (a3 a2 a1 -- a2 a1)
-popop = (a2 a1 --)
-rest = ([a1 .1.] -- [.1.])
-rolldown = (a1 a2 a3 -- a2 a3 a1)
-rollup = (a1 a2 a3 -- a3 a1 a2)
-rrest = ([a1 a2 .1.] -- [.1.])
-second = ([a1 a2 .1.] -- a2)
-swap = (a1 a2 -- a2 a1)
-swons = ([.1.] a1 -- [a1 .1.])
-third = ([a1 a2 a3 .1.] -- a3)
-tuck = (a2 a1 -- a1 a2 a1)
-uncons = ([a1 .1.] -- a1 [.1.])
-
-
-
-
-
-
-

Part V: Functions that use the Stack

-

Consider the stack function which grabs the whole stack, quotes it, -and puts it on itself:

-
stack (...     -- ... [...]        )
-stack (... a   -- ... a [a ...]    )
-stack (... b a -- ... b a [a b ...])
-
-
-

We would like to represent this in Python somehow. To do this we use a -simple, elegant trick.

-
stack         S   -- (         S,           S)
-stack     (a, S)  -- (     (a, S),      (a, S))
-stack (a, (b, S)) -- ( (a, (b, S)), (a, (b, S)))
-
-
-

Instead of representing the stack effect comments as a single tuple -(with N items in it) we use the same cons-list structure to hold the -sequence and unify() the whole comments.

-
-

stack∘uncons

-

Let’s try composing stack and uncons. We want this result:

-
stack∘uncons (... a -- ... a a [...])
-
-
-

The stack effects are:

-
stack = S -- (S, S)
-
-uncons = ((a, Z), S) -- (Z, (a, S))
-
-
-

Unifying:

-
  S    -- (S, S) ∘ ((a, Z), S) -- (Z, (a,   S   ))
-                                                    w/ { S: (a, Z) }
-(a, Z) --        ∘             -- (Z, (a, (a, Z)))
-
-
-

So:

-
stack∘uncons == (a, Z) -- (Z, (a, (a, Z)))
-
-
-

It works.

-
-
-

stack∘uncons∘uncons

-

Let’s try stack∘uncons∘uncons:

-
(a, S     ) -- (S,      (a, (a, S     ))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
-
-                                                                                w/ { S: (b, Z) }
-
-(a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z),  S`             ) -- (Z, (b,   S`   ))
-
-                                                                                w/ { S`: (a, (a, (b, Z))) }
-
-(a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), (a, (a, (b, Z)))) -- (Z, (b, (a, (a, (b, Z)))))
-
-(a, (b, Z)) -- (Z, (b, (a, (a, (b, Z)))))
-
-
-

It works.

-
-

compose() version 2

-

This function has to be modified to use the new datastructures and it is -no longer recursive, instead recursion happens as part of unification. -Further, the first and second of Pöial’s rules are now handled -automatically by the unification algorithm. (One easy way to see this is -that now an empty stack effect comment is represented by a -StackJoyType instance which is not “falsey” and so neither of the -first two rules’ if clauses will ever be True. Later on I change -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))
-
-
-

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
-
-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)
-
-
-
((a1, s1), (s1, (a1, (a1, s1))))
-
-
-
reduce(C, (stack, uncons, uncons))
-
-
-
((a1, (a2, s1)), (s1, (a2, (a1, (a1, (a2, s1))))))
-
-
-

The display function should be changed too.

-
-
-
-

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)
-
-
-
ccons = (a1 a2 [.1.] -- [a1 a2 .1.])
-cons = (a1 [.1.] -- [a1 .1.])
-divmod_ = (n2 n1 -- n4 n3)
-dup = (a1 -- a1 a1)
-dupd = (a2 a1 -- a2 a2 a1)
-first = ([a1 .1.] -- a1)
-mul = (n1 n2 -- n3)
-over = (a2 a1 -- a2 a1 a2)
-pm = (n2 n1 -- n4 n3)
-pop = (a1 --)
-popd = (a2 a1 -- a1)
-popdd = (a3 a2 a1 -- a2 a1)
-popop = (a2 a1 --)
-pred = (n1 -- n2)
-rest = ([a1 .1.] -- [.1.])
-rolldown = (a1 a2 a3 -- a2 a3 a1)
-rollup = (a1 a2 a3 -- a3 a1 a2)
-rrest = ([a1 a2 .1.] -- [.1.])
-second = ([a1 a2 .1.] -- a2)
-sqrt = (n1 -- n2)
-stack = (... -- ... [...])
-succ = (n1 -- n2)
-swaack = ([.1.] -- [.0.])
-swap = (a1 a2 -- a2 a1)
-swons = ([.1.] a1 -- [a1 .1.])
-third = ([a1 a2 a3 .1.] -- a3)
-tuck = (a2 a1 -- a1 a2 a1)
-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)))
-
-
-
(... -- ... [...])
-
-(... a1 -- ... a1 a1 [...])
-
-(... a2 a1 -- ... a2 a1 a1 a2 [...])
-
-(... a1 -- ... a1 [a1 ...])
-
-
-
print doc_from_stack_effect(*C(ccons, stack))
-
-
-
(... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])
-
-
-
Q = C(ccons, stack)
-
-Q
-
-
-
((s1, (a1, (a2, s2))), (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2)))
-
-
-
-

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)
-
-
-
print compile_('Q', Q)
-
-
-
def Q(stack):
-    """(... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])"""
-    (s1, (a1, (a2, s2))) = stack
-    return (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2))
-
-
-
unstack = (S[1], S[0]), S[1]
-enstacken = S[0], (S[0], S[1])
-
-
-
print doc_from_stack_effect(*unstack)
-
-
-
([.1.] --)
-
-
-
print doc_from_stack_effect(*enstacken)
-
-
-
(-- [.0.])
-
-
-
print doc_from_stack_effect(*C(cons, unstack))
-
-
-
(a1 [.1.] -- a1)
-
-
-
print doc_from_stack_effect(*C(cons, enstacken))
-
-
-
(a1 [.1.] -- [[a1 .1.] .2.])
-
-
-
C(cons, unstack)
-
-
-
((s1, (a1, s2)), (a1, s1))
-
-
-
-
-
-
-

Part VI: Multiple Stack Effects

-

-
class IntJoyType(NumberJoyType): prefix = 'i'
-
-
-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])),
-]
-
-
-
for f in muls:
-    print doc_from_stack_effect(*f)
-
-
-
(i1 i2 -- i3)
-(i1 f2 -- f3)
-(f1 i2 -- f3)
-(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)
-
-
-
(a1 -- a1 a1) (i1 i2 -- i3) (i1 -- i2)
-(a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2)
-
-
-
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 MC(F, G):
-    return sorted(set(meta_compose(F, G)))
-
-
-
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)
-
-
-
(f1 -- f2)
-(i1 -- i2)
-
-
-
-

Representing an Unbounded Sequence of Types

-

We can borrow a trick from Brzozowski’s Derivatives of Regular -Expressions to -invent a new type of type variable, a “sequence type” (I think this is -what they mean in the literature by that term…) or “Kleene -Star” type. I’m going to -represent it as a type letter and the asterix, so a sequence of zero or -more AnyJoyType variables would be:

-
A*
-
-
-

The A* works by splitting the universe into two alternate histories:

-
A* -> 0 | A A*
-
-
-

The Kleene star variable disappears in one universe, and in the other it -turns into an AnyJoyType variable followed by itself again. We have -to return all universes (represented by their substitution dicts, the -“unifiers”) that don’t lead to type conflicts.

-

Consider unifying two stacks (the lowercase letters are any type -variables of the kinds we have defined so far):

-
[a A* b .0.] U [c d .1.]
-                          w/ {c: a}
-[  A* b .0.] U [  d .1.]
-
-
-

Now we have to split universes to unify A*. In the first universe it -disappears:

-
[b .0.] U [d .1.]
-                   w/ {d: b, .1.: .0.}
-     [] U []
-
-
-

While in the second it spawns an A, which we will label e:

-
[e A* b .0.] U [d .1.]
-                        w/ {d: e}
-[  A* b .0.] U [  .1.]
-                        w/ {.1.: A* b .0.}
-[  A* b .0.] U [  A* b .0.]
-
-
-

Giving us two unifiers:

-
{c: a,  d: b,  .1.:      .0.}
-{c: a,  d: e,  .1.: A* b .0.}
-
-
-
class KleeneStar(object):
-
-    kind = AnyJoyType
-
-    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 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 __ge__(self, other):
-        return self.kind >= other.kind
-
-    def __add__(self, other):
-        return self.__class__(self.number + other)
-    __radd__ = __add__
-
-    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
-
-
-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
-
-
-
(a1*, s1)
-
-
-
b = (A[1], S[2])
-b
-
-
-
(a1, s2)
-
-
-
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)
-
-
-
{s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2)
-{a1: a10002, s2: (a1*, s1)} -> (a1*, s1) (a10002, (a1*, s1))
-
-
-
(a1*, s1)       [a1*]       (a1, s2)        [a1]
-
-(a1*, (a1, s2)) [a1* a1]    (a1, s2)        [a1]
-
-(a1*, s1)       [a1*]       (a2, (a1*, s1)) [a2 a1*]
-
-
-
sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0])
-
-print doc_from_stack_effect(*sum_)
-
-
-
([n1* .1.] -- n0)
-
-
-
f = (N[1], (N[2], (N[3], S[1]))), S[0]
-
-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])
-
-
-
{s1: (n1, (n2, (n3, s1)))} -> (n0, s0)
-{n1: n10001, s1: (n2, (n3, s1))} -> (n0, s0)
-{n1: n10001, s1: (n3, s1), n2: n10002} -> (n0, s0)
-{n1: n10001, s1: (n1*, s1), n3: n10003, n2: n10002} -> (n0, s0)
-
-
-
-
-

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 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)
-
-
-
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)
-
-
-
([n1* .1.] -- [n1* .1.] n1)
-
-
-
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_),
-
-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
-
-
-
(a4, (a1*, (a3, s1)))
-
-
-
b = (A[1], (A[2], S[2]))
-b
-
-
-
(a1, (a2, s2))
-
-
-
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
-
-
-
{s2: s1, a2: a3, a4: a1}
-{s2: (a1*, (a3, s1)), a2: a10004, a4: a1}
-
-
-
-
-
-
-

Part VII: Typing Combinators

-

In order to compute the stack effect of combinators you kinda have to -have the quoted programs they expect available. In the most general -case, the i combinator, you can’t say anything about its stack -effect other than it expects one quote:

-
i (... [.1.] -- ... .1.)
-
-
-

Or

-
i (... [A* .1.] -- ... A*)
-
-
-

Consider the type of:

-
[cons] dip
-
-
-

Obviously it would be:

-
(a1 [..1] a2 -- [a1 ..1] a2)
-
-
-

dip itself could have:

-
(a1 [..1] -- ... then what?
-
-
-

Without any information about the contents of the quote we can’t say -much about the result.

-
-

Hybrid Inferencer/Interpreter

-

I think there’s a way forward. If we convert our list (of terms we are -composing) into a stack structure we can use it as a Joy expression, -then we can treat the output half of a function’s stack effect comment -as a Joy interpreter stack, and just execute combinators directly. We -can hybridize the compostition function with an interpreter to evaluate -combinators, compose non-combinator functions, and put type variables on -the stack. For combinators like branch that can have more than one -stack effect we have to “split universes” again and return both.

-
-

Joy Types for Functions

-

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):
-
-    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 __repr__(self):
-        return self.name
-
-
-
-
-

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'
-
-
-

For combinators the list contains Python functions.

-
class CombinatorJoyType(FunctionJoyType):
-
-    prefix = 'C'
-
-    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]
-
-
-

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
-
-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_false(stack, expression, dictionary):
-    (then, (else_, (flag, stack))) = stack
-    return stack, concat(else_, expression), dictionary
-
-branch = CombinatorJoyType('branch', [branch_true, branch_false], 100)
-
-
-

You can also provide an optional stack effect, input-side only, that -will then be used as an identity function (that accepts and returns -stacks that match the “guard” stack effect) which will be used to guard -against type mismatches going into the evaluation of the combinator.

-
-
-

infer()

-

With those in place, we can define a function that accepts a sequence of -Joy type variables, including ones representing functions (not just -values), and attempts to grind out all the possible stack effects of -that expression.

-

One tricky thing is that type variables in the expression have to be -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.
-
-
-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]
-
-    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)
-
-    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)
-
-    else:
-        fi, fo = F
-        res = _infer(e, (fi, (n, fo)))
-
-    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 _log_it(e, F):
-    _log.info(
-        u'%3i %s ∘ %s',
-        len(inspect_stack()),
-        doc_from_stack_effect(*F),
-        expression_to_string(e),
-        )
-
-
-
-
-

Work in Progress

-

And that brings us to current Work-In-Progress. The mixed-mode -inferencer/interpreter infer() function seems to work well. There -are details I should document, and the rest of the code in the types -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..)
-
-logging.basicConfig(format='%(message)s', stream=sys.stdout, level=logging.INFO)
-
-globals().update(FUNCTIONS)
-
-h = infer((pred, s2), (mul, s3), (div, s4), (nullary, (bool, s5)), dipd, branch)
-
-print '-' * 40
-
-for fi, fo in h:
-    print doc_from_stack_effect(fi, fo)
-
-
-
---------------------------------------------------------------------------
-
-ZeroDivisionError                         Traceback (most recent call last)
-
-<ipython-input-1-9a9d60354c35> in <module>()
-----> 1 1/0  # (Don't try to run this cell!  It's not going to work.  This is "read only" code heh..)
-      2
-      3 logging.basicConfig(format='%(message)s', stream=sys.stdout, level=logging.INFO)
-      4
-      5 globals().update(FUNCTIONS)
-
-
-ZeroDivisionError: integer division or modulo by zero
-
-
-

The numbers at the start of the lines are the current depth of the -Python call stack. They’re followed by the current computed stack effect -(initialized to ID) then the pending expression (the inference of -the stack effect of which is the whole object of the current example.)

-

In this example we are implementing (and inferring) ifte as -[nullary bool] dipd branch which shows off a lot of the current -implementation in action.

-
  7 (--) ∘ [pred] [mul] [div] [nullary bool] dipd branch
-  8 (-- [pred ...2]) ∘ [mul] [div] [nullary bool] dipd branch
-  9 (-- [pred ...2] [mul ...3]) ∘ [div] [nullary bool] dipd branch
- 10 (-- [pred ...2] [mul ...3] [div ...4]) ∘ [nullary bool] dipd branch
- 11 (-- [pred ...2] [mul ...3] [div ...4] [nullary bool ...5]) ∘ dipd branch
- 15 (-- [pred ...5]) ∘ nullary bool [mul] [div] branch
- 19 (-- [pred ...2]) ∘ [stack] dinfrirst bool [mul] [div] branch
- 20 (-- [pred ...2] [stack ]) ∘ dinfrirst bool [mul] [div] branch
- 22 (-- [pred ...2] [stack ]) ∘ dip infra first bool [mul] [div] branch
- 26 (--) ∘ stack [pred] infra first bool [mul] [div] branch
- 29 (... -- ... [...]) ∘ [pred] infra first bool [mul] [div] branch
- 30 (... -- ... [...] [pred ...1]) ∘ infra first bool [mul] [div] branch
- 34 (--) ∘ pred s1 swaack first bool [mul] [div] branch
- 37 (n1 -- n2) ∘ [n1] swaack first bool [mul] [div] branch
- 38 (... n1 -- ... n2 [n1 ...]) ∘ swaack first bool [mul] [div] branch
- 41 (... n1 -- ... n1 [n2 ...]) ∘ first bool [mul] [div] branch
- 44 (n1 -- n1 n2) ∘ bool [mul] [div] branch
- 47 (n1 -- n1 b1) ∘ [mul] [div] branch
- 48 (n1 -- n1 b1 [mul ...1]) ∘ [div] branch
- 49 (n1 -- n1 b1 [mul ...1] [div ...2]) ∘ branch
- 53 (n1 -- n1) ∘ div
- 56 (f2 f1 -- f3) ∘
- 56 (i1 f1 -- f2) ∘
- 56 (f1 i1 -- f2) ∘
- 56 (i2 i1 -- f1) ∘
- 53 (n1 -- n1) ∘ mul
- 56 (f2 f1 -- f3) ∘
- 56 (i1 f1 -- f2) ∘
- 56 (f1 i1 -- f2) ∘
- 56 (i2 i1 -- i3) ∘
-----------------------------------------
-(f2 f1 -- f3)
-(i1 f1 -- f2)
-(f1 i1 -- f2)
-(i2 i1 -- f1)
-(i2 i1 -- i3)
-
-
-
-
-
-
-

Conclusion

-

We built a simple type inferencer, and a kind of crude “compiler” for a -subset of Joy functions. Then we built a more powerful inferencer that -actually does some evaluation and explores branching code paths

-

Work remains to be done:

-
    -
  • the rest of the library has to be covered

  • -
  • figure out how to deal with loop and genrec, etc..

  • -
  • extend the types to check values (see the appendix)

  • -
  • other kinds of “higher order” type variables, OR, AND, etc..

  • -
  • maybe rewrite in Prolog for great good?

  • -
  • definitions

    -
      -
    • don’t permit composition of functions that don’t compose

    • -
    • auto-compile compilable functions

    • -
    -
  • -
  • Compiling more than just the Yin functions.

  • -
  • getting better visibility (than Python debugger.)

  • -
  • DOOOOCS!!!! Lots of docs!

    -
      -
    • docstrings all around

    • -
    • improve this notebook (it kinda falls apart at the end -narratively. I went off and just started writing code to see if it -would work. It does, but now I have to come back and describe here -what I did.

    • -
    -
  • -
-
-
-

Appendix: Joy in the Logical Paradigm

-

For type checking to work the type label classes have to be modified -to let T >= t succeed, where e.g. T is IntJoyType and t -is int. If you do that you can take advantage of the logical -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
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/Zipper.html b/docs/sphinx_docs/_build/html/notebooks/Zipper.html deleted file mode 100644 index 7eec7cd..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/Zipper.html +++ /dev/null @@ -1,396 +0,0 @@ - - - - - - - - - Traversing Datastructures with Zippers — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Traversing Datastructures with Zippers

-

This notebook is about using the “zipper” with joy datastructures. See -the Zipper wikipedia -entry or -the original paper: “FUNCTIONAL PEARL The Zipper” by Gérard -Huet

-

Given a datastructure on the stack we can navigate through it, modify -it, and rebuild it using the “zipper” technique.

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

Trees

-

In Joypy there aren’t any complex datastructures, just ints, floats, -strings, Symbols (strings that are names of functions) and sequences -(aka lists, aka quoted literals, aka aggregates, etc…), but we can build -trees out -of sequences.

-
J('[1 [2 [3 4 25 6] 7] 8]')
-
-
-
[1 [2 [3 4 25 6] 7] 8]
-
-
-
-
-

Zipper in Joy

-

Zippers work by keeping track of the current item, the already-seen -items, and the yet-to-be seen items as you traverse a datastructure (the -datastructure used to keep track of these items is the zipper.)

-

In Joy we can do this with the following words:

-
z-down == [] swap uncons swap
-z-up == swons swap shunt
-z-right == [swons] cons dip uncons swap
-z-left == swons [uncons swap] dip swap
-
-
-

Let’s use them to change 25 into 625. The first time a word is used I -show the trace so you can see how it works. If we were going to use -these a lot it would make sense to write Python versions for efficiency, -but see below.

-
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')
-
-
-
                          . [1 [2 [3 4 25 6] 7] 8] z-down
-   [1 [2 [3 4 25 6] 7] 8] . z-down
-   [1 [2 [3 4 25 6] 7] 8] . [] swap uncons swap
-[1 [2 [3 4 25 6] 7] 8] [] . swap uncons swap
-[] [1 [2 [3 4 25 6] 7] 8] . uncons swap
-[] 1 [[2 [3 4 25 6] 7] 8] . swap
-[] [[2 [3 4 25 6] 7] 8] 1 .
-
-
-
V('[] [[2 [3 4 25 6] 7] 8] 1 z-right')
-
-
-
                                  . [] [[2 [3 4 25 6] 7] 8] 1 z-right
-                               [] . [[2 [3 4 25 6] 7] 8] 1 z-right
-          [] [[2 [3 4 25 6] 7] 8] . 1 z-right
-        [] [[2 [3 4 25 6] 7] 8] 1 . z-right
-        [] [[2 [3 4 25 6] 7] 8] 1 . [swons] cons dip uncons swap
-[] [[2 [3 4 25 6] 7] 8] 1 [swons] . cons dip uncons swap
-[] [[2 [3 4 25 6] 7] 8] [1 swons] . dip uncons swap
-                               [] . 1 swons [[2 [3 4 25 6] 7] 8] uncons swap
-                             [] 1 . swons [[2 [3 4 25 6] 7] 8] uncons swap
-                             [] 1 . swap cons [[2 [3 4 25 6] 7] 8] uncons swap
-                             1 [] . cons [[2 [3 4 25 6] 7] 8] uncons swap
-                              [1] . [[2 [3 4 25 6] 7] 8] uncons swap
-         [1] [[2 [3 4 25 6] 7] 8] . uncons swap
-         [1] [2 [3 4 25 6] 7] [8] . swap
-         [1] [8] [2 [3 4 25 6] 7] .
-
-
-
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')
-
-
-
[1] [8] [2] [7] [3 4 25 6]
-
-
-
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')
-
-
-
[1] [8] [2] [7] [3] [25 6] 4
-
-
-
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')
-
-
-
[1] [8] [2] [7] [4 3] [6] 625
-
-
-
V('[1] [8] [2] [7] [4 3] [6] 625 z-up')
-
-
-
                              . [1] [8] [2] [7] [4 3] [6] 625 z-up
-                          [1] . [8] [2] [7] [4 3] [6] 625 z-up
-                      [1] [8] . [2] [7] [4 3] [6] 625 z-up
-                  [1] [8] [2] . [7] [4 3] [6] 625 z-up
-              [1] [8] [2] [7] . [4 3] [6] 625 z-up
-        [1] [8] [2] [7] [4 3] . [6] 625 z-up
-    [1] [8] [2] [7] [4 3] [6] . 625 z-up
-[1] [8] [2] [7] [4 3] [6] 625 . z-up
-[1] [8] [2] [7] [4 3] [6] 625 . swons swap shunt
-[1] [8] [2] [7] [4 3] [6] 625 . swap cons swap shunt
-[1] [8] [2] [7] [4 3] 625 [6] . cons swap shunt
-[1] [8] [2] [7] [4 3] [625 6] . swap shunt
-[1] [8] [2] [7] [625 6] [4 3] . shunt
-  [1] [8] [2] [7] [3 4 625 6] .
-
-
-
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')
-
-
-
[1 [2 [3 4 625 6] 7] 8]
-
-
-
-
-

dip and infra

-

In Joy we have the dip and infra combinators which can “target” -or “address” any particular item in a Joy tree structure.

-
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
-                                         [1 [2 [3 4 25 6] 7] 8] . [[[[[[sqr] dipd] infra] dip] infra] dip] infra
-[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] . infra
-                                           8 [2 [3 4 25 6] 7] 1 . [[[[[sqr] dipd] infra] dip] infra] dip [] swaack
-        8 [2 [3 4 25 6] 7] 1 [[[[[sqr] dipd] infra] dip] infra] . dip [] swaack
-                                             8 [2 [3 4 25 6] 7] . [[[[sqr] dipd] infra] dip] infra 1 [] swaack
-                  8 [2 [3 4 25 6] 7] [[[[sqr] dipd] infra] dip] . infra 1 [] swaack
-                                                 7 [3 4 25 6] 2 . [[[sqr] dipd] infra] dip [8] swaack 1 [] swaack
-                            7 [3 4 25 6] 2 [[[sqr] dipd] infra] . dip [8] swaack 1 [] swaack
-                                                   7 [3 4 25 6] . [[sqr] dipd] infra 2 [8] swaack 1 [] swaack
-                                      7 [3 4 25 6] [[sqr] dipd] . infra 2 [8] swaack 1 [] swaack
-                                                       6 25 4 3 . [sqr] dipd [7] swaack 2 [8] swaack 1 [] swaack
-                                                 6 25 4 3 [sqr] . dipd [7] swaack 2 [8] swaack 1 [] swaack
-                                                           6 25 . sqr 4 3 [7] swaack 2 [8] swaack 1 [] swaack
-                                                           6 25 . dup mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack
-                                                        6 25 25 . mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack
-                                                          6 625 . 4 3 [7] swaack 2 [8] swaack 1 [] swaack
-                                                        6 625 4 . 3 [7] swaack 2 [8] swaack 1 [] swaack
-                                                      6 625 4 3 . [7] swaack 2 [8] swaack 1 [] swaack
-                                                  6 625 4 3 [7] . swaack 2 [8] swaack 1 [] swaack
-                                                  7 [3 4 625 6] . 2 [8] swaack 1 [] swaack
-                                                7 [3 4 625 6] 2 . [8] swaack 1 [] swaack
-                                            7 [3 4 625 6] 2 [8] . swaack 1 [] swaack
-                                            8 [2 [3 4 625 6] 7] . 1 [] swaack
-                                          8 [2 [3 4 625 6] 7] 1 . [] swaack
-                                       8 [2 [3 4 625 6] 7] 1 [] . swaack
-                                        [1 [2 [3 4 625 6] 7] 8] .
-
-
-

If you read the trace carefully you’ll see that about half of it is the -dip and infra combinators de-quoting programs and “digging” into -the subject datastructure. Instead of maintaining temporary results on -the stack they are pushed into the pending expression (continuation). -When sqr has run the rest of the pending expression rebuilds the -datastructure.

-
-
-

Z

-

Imagine a function Z that accepts a sequence of dip and -infra combinators, a quoted program [Q], and a datastructure to -work on. It would effectively execute the quoted program as if it had -been embedded in a nested series of quoted programs, e.g.:

-
   [...] [Q] [dip dip infra dip infra dip infra] Z
--------------------------------------------------------------
-   [...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra
-
-
-

The Z function isn’t hard to make.

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

Here it is in action in a simplified scenario.

-
V('1 [2 3 4] Z')
-
-
-
                             . 1 [2 3 4] Z
-                           1 . [2 3 4] Z
-                   1 [2 3 4] . Z
-                   1 [2 3 4] . [[] cons cons] step i
-    1 [2 3 4] [[] cons cons] . step i
-          1 2 [[] cons cons] . i [3 4] [[] cons cons] step i
-                         1 2 . [] cons cons [3 4] [[] cons cons] step i
-                      1 2 [] . cons cons [3 4] [[] cons cons] step i
-                       1 [2] . cons [3 4] [[] cons cons] step i
-                       [1 2] . [3 4] [[] cons cons] step i
-                 [1 2] [3 4] . [[] cons cons] step i
-  [1 2] [3 4] [[] cons cons] . step i
-      [1 2] 3 [[] cons cons] . i [4] [[] cons cons] step i
-                     [1 2] 3 . [] cons cons [4] [[] cons cons] step i
-                  [1 2] 3 [] . cons cons [4] [[] cons cons] step i
-                   [1 2] [3] . cons [4] [[] cons cons] step i
-                   [[1 2] 3] . [4] [[] cons cons] step i
-               [[1 2] 3] [4] . [[] cons cons] step i
-[[1 2] 3] [4] [[] cons cons] . step i
-  [[1 2] 3] 4 [[] cons cons] . i i
-                 [[1 2] 3] 4 . [] cons cons i
-              [[1 2] 3] 4 [] . cons cons i
-               [[1 2] 3] [4] . cons i
-               [[[1 2] 3] 4] . i
-                             . [[1 2] 3] 4
-                   [[1 2] 3] . 4
-                 [[1 2] 3] 4 .
-
-
-

And here it is doing the main thing.

-
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]
-
-
-
-
-

Addressing

-

Because we are only using two combinators we could replace the list with -a string made from only two characters.

-
   [...] [Q] 'ddididi' Zstr
--------------------------------------------------------------
-   [...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra
-
-
-

The string can be considered a name or address for an item in the -subject datastructure.

-
-
-

Determining the right “path” for an item in a tree.

-

It’s easy to read off (in reverse) the right sequence of “d” and “i” -from the subject datastructure:

-
[ n [ n [ n n x ...
-i d i d i d d Bingo!
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/notebooks/index.html b/docs/sphinx_docs/_build/html/notebooks/index.html deleted file mode 100644 index 26bd28c..0000000 --- a/docs/sphinx_docs/_build/html/notebooks/index.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - - - - - Essays about Programming in Joy — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Essays about Programming in Joy

-

These essays are adapted from Jupyter notebooks. I hope to have those hosted somewhere where people can view them “live” and interact with them, possibly on MS Azure. For now, Sphinx does such a great job rendering the HTML that I am copying over some notebooks in ReST format and hand-editing them into these documents.

-
- -
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/objects.inv b/docs/sphinx_docs/_build/html/objects.inv deleted file mode 100644 index fa8de68c1271b4703ed03127991cefce3a8d4099..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1599 zcmV-F2Eh3vAX9K?X>NERX>N99Zgg*Qc_4OWa&u{KZXhxWBOp+6Z)#;@bUGkZXmxH1 zBOq2~a&u{KZaN?^E;I@wAXI2&AaZ4GVQFq;WpW^IW*~HEX>%ZEX>4U6X>%ZBZ*6dL zWpi_7WFU2OX>MmAdTeQ8E(&nSkP9%D6bd-AQZos2t44gJ< zD+w`4zyPS9o-#f475V~wuslf@1Sx?EX?cxaEDQL)Z-K>Pv4B3Q?evq{GQB-3RbCgs zUNihYUAnUPCbXP<%T6Yr0&aR=JydF4-EPa7DlUyt##3Ppo?eW>gpJ*kTb(g-vw>kpc}frH?qQy_i7=0J&QWN1+`J70wP+7;t15`BL3iAueRk=~L zx!0QLt$CpoDL@t?CvBkxR0af%;iQ9-LRmsV3tLG7(-uw69chnB+F+`=;WUDD5_9XH zv_Vx?7&&_phvY4cKT^P!oVL;>-_Y=~BH=YDP_==ahLW!T+NL(C)3ET|JM5@} zzdoi3ATcpFdX4`Z&>*OAr@+}n;QNc3ekl;e)@3Ta)iNv3K^Wi)@E zJ44(tvdUqD?fF^3XHc+{Q`WUMICka#o$O(`5*`#G?(jy-UQd6Vp0W!i>Jlo)y*)p+ zn9}`n!G6Z}tL7IK3?(oV+>kL2zXn|Qa&Or?qiPK~n{8h)Ft2t!Y%Q^ZyWDX9&~GPQ zf!`O~ZT3Cw2IgR(5-`EA9B_f&o^&07`5{Dfa7LvZ%#?bt-<@N+Stug~FJhyEfFKkz zu8mq4UY58{k>&*$xk3l7z-DTm-N2$QxXCVe@oR@o9p{A+eEIvYo6DZP6%VWv z`U5}0^KJ?l4t`Z5)psEoE0eX5kx_q*3s&x}H?Uz&u@(aCH(u1Z%6l>fkx|3CP1im? z&zhjaQC@E`16Gm7FR*s1I=SI`X)!Ve#rl|_8rr^m{>QSARbx$cuX7yn$eefGt&(Ex z_ekQS$uUCnEd0)v-5D5D8$z}dH-PbgZVc?JGuC2Rz=rn7=&v=;(bG~4TiSI8`8|5B zOo_o3DcyjmO_OZTRXIazxWXgjAA|-AyDk=W^{nWEi_ys4b$4nVdY@P@BHR+#g>1f~ zPa^f($C?|+ZnZRH+q(w|RzeeNS#4@+qVHVg5Xs*yA$yBg(Cnl3;XS^w2Y_8*1M?kz zJ~?mlZowioHOI|5_fO@(erhHdoA+z)U;c(|w!OoFgpuT0K&-gcaJ~fbFuEWyqE*Hg z)-@ey*>RD`0dMelweuQXUBH54O83)7j2}clCH*0rA8-dnLti&r?w^jmzy)_457Jt= z8k1-^Z2~k7!>b=N2AoXx7rO_gFrC`TXz19fpL90>OvTRn;EqJ^~KC^B=PTPyN2%_EG=< diff --git a/docs/sphinx_docs/_build/html/parser.html b/docs/sphinx_docs/_build/html/parser.html deleted file mode 100644 index 257d976..0000000 --- a/docs/sphinx_docs/_build/html/parser.html +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - - Parsing Text into Joy Expressions — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Parsing Text into Joy Expressions

-

TODO: example…

-
-

joy.parser

-

This module exports a single function for converting text to a joy -expression as well as a single Symbol class and a single Exception type.

-

The Symbol string class is used by the interpreter to recognize literals -by the fact that they are not Symbol objects.

-

A crude grammar:

-
joy = term*
-term = integer | '[' joy ']' | symbol
-
-
-

A Joy expression is a sequence of zero or more terms. A term is a -literal value (integer or Joy expression) or a function symbol. -Function symbols are sequences of non-blanks and cannot contain square -brackets. Terms must be separated by blanks, which can be omitted -around square brackets.

-
-
-exception joy.parser.ParseError[source]
-

Raised when there is a error while parsing text.

-
- -
-
-class joy.parser.Symbol[source]
-

A string class that represents Joy function names.

-
- -
-
-joy.parser.text_to_expression(text)[source]
-

Convert a string to a Joy expression.

-

When supplied with a string this function returns a Python datastructure -that represents the Joy datastructure described by the text expression. -Any unbalanced square brackets will raise a ParseError.

-
-
Parameters
-

text (str) – Text to convert.

-
-
Return type
-

stack

-
-
Raises
-

ParseError – if the parse fails.

-
-
-
- -
-
-

Parser Internals

-

TODO: Document things like the regular expressions used for tokenizing, and the re.Scanner, etc…

-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/pretty.html b/docs/sphinx_docs/_build/html/pretty.html deleted file mode 100644 index 8d609eb..0000000 --- a/docs/sphinx_docs/_build/html/pretty.html +++ /dev/null @@ -1,189 +0,0 @@ - - - - - - - - - Tracing Joy Execution — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Tracing Joy Execution

-
-

joy.utils.pretty_print

-

Pretty printing support, e.g.:

-
Joy? [23 18 * 99 +] trace
-       • 23 18 mul 99 add
-    23 • 18 mul 99 add
- 23 18 • mul 99 add
-   414 • 99 add
-414 99 • add
-   513 • 
-
-513 <-top
-
-joy? 
-
-
-

On each line the stack is printed with the top to the left, then a -bullet symbol, •, to represent the current locus of processing, then -the pending expression to the right.

-
-
-class joy.utils.pretty_print.TracePrinter[source]
-

This is what does the formatting. You instantiate it and pass the viewer() -method to the joy.joy.joy() function, then print it to see the -trace.

-
-
-go()[source]
-

Return a list of strings, one for each entry in the history, prefixed -with enough spaces to align all the interpreter dots.

-

This method is called internally by the __str__() method.

-
-
Return type
-

list(str)

-
-
-
- -
-
-viewer(stack, expression)[source]
-

Record the current stack and expression in the TracePrinter’s history. -Pass this method as the viewer argument to the joy.joy.joy() function.

-
-
Parameters
-
    -
  • quote (stack) – A stack.

  • -
  • expression (stack) – A stack.

  • -
-
-
-
- -
- -
-
-joy.utils.pretty_print.trace(stack, expression, dictionary)[source]
-

Evaluate a Joy expression on a stack and print a trace.

-

This function is just like the i combinator but it also prints a -trace of the evaluation

-
-
Parameters
-
    -
  • stack (stack) – The stack.

  • -
  • expression (stack) – The expression to evaluate.

  • -
  • dictionary (dict) – A dict mapping names to Joy functions.

  • -
-
-
Return type
-

(stack, (), dictionary)

-
-
-
- -
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/py-modindex.html b/docs/sphinx_docs/_build/html/py-modindex.html deleted file mode 100644 index 3a3c124..0000000 --- a/docs/sphinx_docs/_build/html/py-modindex.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - Python Module Index — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- - -

Python Module Index

- -
- j -
- - - - - - - - - - - - - - - - - - - - - - - - - -
 
- j
- joy -
    - joy.joy -
    - joy.library -
    - joy.parser -
    - joy.utils.generated_library -
    - joy.utils.pretty_print -
    - joy.utils.stack -
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/search.html b/docs/sphinx_docs/_build/html/search.html deleted file mode 100644 index 3c0ea74..0000000 --- a/docs/sphinx_docs/_build/html/search.html +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - Search — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -

Search

- - - - -

- Searching for multiple words only shows matches that contain - all words. -

- - -
- - - -
- - - -
- -
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/searchindex.js b/docs/sphinx_docs/_build/html/searchindex.js deleted file mode 100644 index f8978f3..0000000 --- a/docs/sphinx_docs/_build/html/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({docnames:["index","joy","lib","library","notebooks/Categorical","notebooks/Derivatives_of_Regular_Expressions","notebooks/Developing","notebooks/Generator_Programs","notebooks/Intro","notebooks/Newton-Raphson","notebooks/NoUpdates","notebooks/Ordered_Binary_Trees","notebooks/Quadratic","notebooks/Recursion_Combinators","notebooks/Replacing","notebooks/Square_Spiral","notebooks/The_Four_Operations","notebooks/Treestep","notebooks/TypeChecking","notebooks/Types","notebooks/Zipper","notebooks/index","parser","pretty","stack","types"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,"sphinx.ext.todo":2,"sphinx.ext.viewcode":1,sphinx:56},filenames:["index.rst","joy.rst","lib.rst","library.rst","notebooks/Categorical.rst","notebooks/Derivatives_of_Regular_Expressions.rst","notebooks/Developing.rst","notebooks/Generator_Programs.rst","notebooks/Intro.rst","notebooks/Newton-Raphson.rst","notebooks/NoUpdates.rst","notebooks/Ordered_Binary_Trees.rst","notebooks/Quadratic.rst","notebooks/Recursion_Combinators.rst","notebooks/Replacing.rst","notebooks/Square_Spiral.rst","notebooks/The_Four_Operations.rst","notebooks/Treestep.rst","notebooks/TypeChecking.rst","notebooks/Types.rst","notebooks/Zipper.rst","notebooks/index.rst","parser.rst","pretty.rst","stack.rst","types.rst"],objects:{"joy.joy":[[1,1,1,"","UnknownSymbolError"],[1,2,1,"","interp"],[1,2,1,"","joy"],[1,2,1,"","repl"],[1,2,1,"","run"]],"joy.library":[[3,2,1,"","BinaryLogicWrapper"],[3,2,1,"","BinaryMathWrapper"],[3,3,1,"","Def"],[3,2,1,"","FunctionWrapper"],[3,2,1,"","SimpleFunctionWrapper"],[3,2,1,"","UnaryBuiltinWrapper"],[3,2,1,"","add_aliases"],[3,2,1,"","app1"],[3,2,1,"","app2"],[3,2,1,"","app3"],[3,2,1,"","b"],[3,2,1,"","branch"],[3,2,1,"","choice"],[3,2,1,"","clear"],[3,2,1,"","cmp_"],[3,2,1,"","concat_"],[3,2,1,"","cond"],[3,2,1,"","dip"],[3,2,1,"","dipd"],[3,2,1,"","dipdd"],[3,2,1,"","disenstacken"],[3,2,1,"","divmod_"],[3,2,1,"","drop"],[3,2,1,"","dupdip"],[3,2,1,"","floor"],[3,2,1,"","gcd2"],[3,2,1,"","genrec"],[3,2,1,"","getitem"],[3,2,1,"","help_"],[3,2,1,"","i"],[3,2,1,"","id_"],[3,2,1,"","ifte"],[3,2,1,"","ii"],[3,2,1,"","infra"],[3,2,1,"","initialize"],[3,2,1,"","inscribe"],[3,2,1,"","inscribe_"],[3,2,1,"","loop"],[3,2,1,"","map_"],[3,2,1,"","max_"],[3,2,1,"","min_"],[3,2,1,"","pm"],[3,2,1,"","pred"],[3,2,1,"","primrec"],[3,2,1,"","remove"],[3,2,1,"","reverse"],[3,2,1,"","select"],[3,2,1,"","sharing"],[3,2,1,"","shunt"],[3,2,1,"","sort_"],[3,2,1,"","sqrt"],[3,2,1,"","step"],[3,2,1,"","succ"],[3,2,1,"","sum_"],[3,2,1,"","take"],[3,2,1,"","times"],[3,2,1,"","unique"],[3,2,1,"","void"],[3,2,1,"","warranty"],[3,2,1,"","words"],[3,2,1,"","x"],[3,2,1,"","zip_"]],"joy.parser":[[22,1,1,"","ParseError"],[22,3,1,"","Symbol"],[22,2,1,"","text_to_expression"]],"joy.utils":[[3,0,0,"-","generated_library"],[23,0,0,"-","pretty_print"],[24,0,0,"-","stack"]],"joy.utils.generated_library":[[3,2,1,"","ccons"],[3,2,1,"","cons"],[3,2,1,"","dup"],[3,2,1,"","dupd"],[3,2,1,"","dupdd"],[3,2,1,"","first"],[3,2,1,"","first_two"],[3,2,1,"","fourth"],[3,2,1,"","over"],[3,2,1,"","pop"],[3,2,1,"","popd"],[3,2,1,"","popdd"],[3,2,1,"","popop"],[3,2,1,"","popopd"],[3,2,1,"","popopdd"],[3,2,1,"","rest"],[3,2,1,"","rolldown"],[3,2,1,"","rollup"],[3,2,1,"","rrest"],[3,2,1,"","second"],[3,2,1,"","stack"],[3,2,1,"","stuncons"],[3,2,1,"","stununcons"],[3,2,1,"","swaack"],[3,2,1,"","swap"],[3,2,1,"","swons"],[3,2,1,"","third"],[3,2,1,"","tuck"],[3,2,1,"","uncons"],[3,2,1,"","unit"],[3,2,1,"","unswons"]],"joy.utils.pretty_print":[[23,3,1,"","TracePrinter"],[23,2,1,"","trace"]],"joy.utils.pretty_print.TracePrinter":[[23,4,1,"","go"],[23,4,1,"","viewer"]],"joy.utils.stack":[[24,2,1,"","concat"],[24,2,1,"","dnd"],[24,2,1,"","expression_to_string"],[24,2,1,"","iter_stack"],[24,2,1,"","list_to_stack"],[24,2,1,"","pick"],[24,2,1,"","stack_to_string"]],joy:[[1,0,0,"-","joy"],[3,0,0,"-","library"],[22,0,0,"-","parser"]]},objnames:{"0":["py","module","Python module"],"1":["py","exception","Python exception"],"2":["py","function","Python function"],"3":["py","class","Python class"],"4":["py","method","Python method"]},objtypes:{"0":"py:module","1":"py:exception","2":"py:function","3":"py:class","4":"py:method"},terms:{"0":[2,3,5,6,7,8,9,10,11,12,14,15,17,18,19,25],"0000000001585":9,"000000001":9,"01":[6,7],"03":19,"05":5,"0a":19,"0b":[6,7],"0b11100111011011":6,"1":[2,3,5,6,7,8,9,10,11,12,14,15,17,18,19,20,24,25],"10":[2,5,6,7,13,19,25],"100":[5,17,19],"1000":[5,6,7,19],"10000":[5,19],"10001":5,"1001":[5,19],"10010":5,"10011":5,"1002":19,"101":5,"1010":5,"10100":5,"10101":5,"1011":5,"10110":5,"10111":5,"102":17,"1024":2,"103":17,"104":17,"105":17,"106":17,"107":17,"108":17,"109":17,"10946":7,"11":[2,6,7,19,25],"110":[5,6],"1100":5,"11000":5,"11001":5,"1101":5,"11010":5,"11011":5,"1110":5,"11100":5,"11101":5,"1111":5,"11110":5,"11111":5,"12":[2,6,17],"120":13,"122":5,"123":8,"128":7,"13":[2,7,17,25],"1346269":7,"14":[2,6,17],"144":7,"14811":[6,7],"15":[2,6,13,17,19,25],"16":[2,7,12,17,25],"160":2,"17":[11,15,17],"18":[6,8,14,15,17,23],"19":[17,19,25],"196418":7,"1a":19,"1b":19,"2":[2,3,5,6,8,9,10,11,13,14,17,18,20,24,25],"20":[2,6,14,19,25],"2006":19,"2017":[8,19],"2020":25,"207":2,"21":[6,7],"22":[9,19,25],"23":[2,6,7,8,9,11,14,15,17,19,23],"230":7,"231":[6,7],"232":7,"233":7,"233168":[6,7],"234":7,"23rd":19,"24":[2,6,7],"25":[6,7,12,17,18,20,25],"256":7,"2584":7,"26":[2,5,7,19,25],"27":[6,7],"273":10,"28":[7,18,25],"29":[19,25],"2a":19,"2b":19,"3":[2,3,7,8,10,11,12,13,17,18,20,21,24,25],"30":[2,6,19,25],"31":18,"32":[2,7,17],"33":6,"34":[7,18,19,25],"36":9,"37":[18,19,25],"3702":[6,7],"38":[19,25],"3819660112501051":12,"3b":19,"3i":19,"4":[2,6,7,8,9,11,13,17,18,20,24,25],"40":[2,18,19],"4000000":7,"41":[14,19,25],"414":23,"44":[11,17,19,25],"45":[2,6],"46":19,"4613732":7,"46368":7,"466":6,"47":[19,25],"48":[19,25],"49":[17,19,25],"4ac":12,"4m":7,"5":[2,3,5,7,8,11,12,13,14,17,19,21,25],"50":2,"513":23,"529":[2,8],"53":[19,25],"547":8,"55":[6,7],"552":2,"5555555555555554":2,"56":[19,25],"57":[6,7],"5bkei":11,"5d":11,"6":[2,6,9,11,13,17,19,20],"60":6,"610":7,"618033988749895":12,"625":20,"64":7,"66":[6,7],"6945":6,"7":[2,6,7,11,17,19,20,25],"75":2,"795831523312719":[2,9],"8":[2,5,6,7,11,12,17,19,20,25],"80":6,"832040":7,"88":11,"8888":8,"89":7,"9":[2,6,11,12,17,19,25],"90":2,"92":5,"925":6,"978":6,"980":6,"981":6,"984":6,"985":6,"987":6,"99":23,"990":6,"991":6,"992":6,"993":6,"995":6,"996":6,"999":[6,7],"999999999999996":9,"9a9d60354c35":19,"\u03b4":5,"\u03b5":9,"abstract":[8,11,24],"boolean":[2,3,8,11,16],"break":[5,8,15,19],"byte":[5,6],"case":[2,3,13,16,17,19,24],"char":5,"class":[3,5,8,19,22,23,24],"const":15,"default":[3,7,11,24],"do":[2,3,4,5,6,7,8,11,13,14,15,16,19,20,21],"export":[3,22],"final":[2,11,13,15],"float":[8,19,20],"function":[0,1,4,6,7,10,12,15,18,20,21,22,23,24,25],"g\u00e9rard":20,"goto":5,"import":[2,5,6,7,9,11,12,13,14,15,17,18,19,20],"int":[5,7,8,13,15,19,20,24],"long":[11,15,19,21],"new":[0,2,3,5,7,8,10,13,14,15,19],"p\u00f6ial":21,"p\u00f6ial06typingtool":19,"public":10,"return":[1,3,5,6,8,11,13,14,16,17,19,22,23,24],"short":15,"static":[2,10],"super":19,"switch":[2,19],"throw":[11,25],"true":[2,3,5,6,13,15,16,19],"try":[7,9,12,13,15,17,18,19,21],"void":[0,3,15],"while":[3,5,8,11,19,22,24],A:[1,3,4,8,13,16,19,21,22,23,24],AND:[5,19],And:[5,6,7,9,11,13,15,16,19,20,24],As:[4,6,11,15,19],At:[6,13,19],Be:2,But:[0,4,6,7,8,11,14,15,19,24],By:[7,11,19],For:[0,2,3,11,13,14,19,21,24],If:[2,3,5,6,7,8,9,10,12,13,15,17,19,20],In:[2,3,4,6,7,8,13,16,19,20,21,24],It:[0,2,3,4,5,6,7,8,10,11,13,15,19,20,24,25],Its:3,NO:8,NOT:5,No:[0,17,21],Not:19,OR:[5,19],Of:6,On:[3,23],One:[2,8,16,19,21],Or:[5,10,11,15,17,19],TOS:[2,3],That:[6,11],The:[0,1,2,3,4,5,7,9,10,12,20,21,22,23,24,25],Then:[2,3,11,12,13,19],There:[5,12,13,15,16,17,19,24],These:[16,19,21,24],To:[0,5,6,7,9,11,13,17,19],With:[9,13,15,19,21,25],_0:5,_1000:19,_1:5,_:[8,14,19],__:11,__add__:19,__call__:5,__class__:19,__eq__:19,__ge__:19,__hash__:19,__init__:[5,19],__main__:19,__radd__:19,__repr__:19,__str__:23,_and:5,_compaction_rul:5,_con:5,_dictionari:19,_f:19,_ge:19,_infer:19,_interpret:19,_log:19,_log_it:19,_names_for:19,_or:5,_r:19,_spn_e:15,_spn_p:15,_spn_t:15,_templat:5,_to_str:19,_tree_add_:11,_tree_add_e:[3,11,25],_tree_add_p:11,_tree_add_r:11,_tree_add_t:11,_tree_delete_:11,_tree_delete_clear_stuff:[3,11,25],_tree_delete_del:11,_tree_delete_r0:[3,11,25],_tree_delete_r1:11,_tree_delete_rightmost:11,_tree_delete_w:11,_tree_get_:[3,11,25],_tree_get_p:11,_tree_get_r:11,_tree_get_t:11,_tree_iter_order_curr:11,_tree_iter_order_left:11,_tree_iter_order_r:11,_tree_iter_order_right:11,_tree_t:11,_treestep_0:17,_treestep_1:17,_uniqu:19,_within_b:9,_within_p:9,_within_r:9,a0:19,a10001:19,a10002:19,a10003:19,a10004:19,a1:[3,18,19,25],a2:[3,18,19,25],a3:[3,18,19,25],a4:[3,18,19,25],a5:[18,19,25],a_:9,a_i:9,aa:13,ab:[0,3,5,9,15],abbrevi:17,abl:[5,16,19,25],about:[0,8,11,16,19,20,24],abov:[0,5,6,9,11,13,16,19,24],absolut:8,ac:5,accept:[0,1,2,3,5,6,7,8,11,12,14,15,16,17,19,20],accord:5,accordingli:[11,16],accumul:6,act:[5,25],action:[0,8,14,15,19,20,21],actual:[2,6,8,11,16,19],ad:[4,5,8,10,14,19,21],adapt:[15,21],add:[3,5,6,7,8,14,19,23,25],add_alias:3,add_def:[],add_definit:[11,17],addit:[0,2,3,6,8,13,14,17],address:21,adjust:11,advantag:19,affect:[3,16],after:[5,6,7,8,13,16,19,24,25],afterward:8,again:[2,3,6,8,11,13,19],against:19,aggreg:20,ahead:19,aka:[5,8,20,25],al:[16,19],albrecht:0,algorithm:[5,8,19],alia:3,alias:[3,8],align:[8,23],all:[3,5,6,7,8,11,13,14,15,16,17,19,23,24],alloc:19,allow:[10,11,16,24],almost:11,along:[5,8,13,19],alphabet:[3,21],alreadi:[5,9,14,19,20],also:[0,5,6,8,11,16,19,23,24],alter:[5,19],altern:[4,19],although:[4,11],altogeth:7,alwai:[6,10,13,16],am:[16,21],amend:16,among:19,amort:11,an:[0,1,2,3,4,5,9,14,15,17,21,24,25],analysi:[4,21],anamorph:[8,21],and_:3,ani:[0,4,5,6,8,10,11,15,16,19,20,22],annual:8,anonym:11,anoth:[5,11,16,19,24,25],anyhow:[16,19],anyjoytyp:19,anymor:19,anystarjoytyp:19,anyth:[2,3,5,8,19,25],apart:19,api:10,app1:3,app2:[3,8,12,13,14,16],app3:[3,16],app:8,appear:[2,4,5,6,11],append:19,appendix:21,appli:[2,3,6,7,11,13,15,19],applic:7,approach:6,appropri:5,approxim:21,apter:24,ar:[1,2,3,5,6,7,8,10,12,13,16,17,19,20,21,22,24,25],archiv:0,aren:20,arg:[2,3,15],argument:[2,3,8,9,12,13,15,21,23,24],arithmet:2,ariti:[2,16],around:[6,19,22,24],arrang:[15,17],arriv:[7,17],arrow:5,art10000350:[],articl:[0,4,7,13],ascii:5,ascii_lowercas:5,ask:[4,7,19],aspect:0,assembl:[5,15],assert:[5,19],assign:[16,24],associ:11,assum:9,asterisk:17,asterix:[19,25],asyncron:16,attack:8,attempt:[0,1,19],attribut:3,attributeerror:19,author:19,auto:[0,19,25],automat:[4,16,19],auxiliari:[5,17],avail:[0,19,25],averag:[8,14],avoid:11,awai:[11,19],awar:2,awkward:[11,13,19],azur:21,b0:3,b1:[3,19,25],b2:25,b3:25,b:[3,5,7,8,9,11,13,16,17,19],back:[3,11,19],backtrack:25,backward:[10,11,12,17],bad:19,bag:8,banana:13,bar:16,barb:13,base:[0,2,3,10,13,17,19],basic:[2,3,8,11],basicconfig:[18,19],bc:5,bd:5,becaas:5,becaus:[2,3,5,8,11,16,17,19,20,24],becom:[0,11,15,17,24],becuas:19,been:[5,9,10,11,19,20],befor:[5,7,8,11],begin:[11,17],behavior:[10,17,25],behaviour:[0,1,19],behind:16,being:[0,16,24],below:[2,3,5,6,7,11,15,19,20],bespok:8,best:0,better:[6,11,13,19],between:[0,6],beyond:7,biannual:8,bin:5,binari:[0,7,8,21],binary_search_tre:11,binarybuiltinwrapp:[],binarylogicwrapp:3,binarymathwrapp:3,bind:8,bingo:20,bit:[5,6,7,11,19],blank:22,bliss:[0,21],block:6,bodi:[2,3,5,8,11,16],body_text:[],booktitl:19,bool:[3,13,19,25],borrow:[8,19],both:[2,6,8,12,13,14,15,16,19,24],bottom:7,bounce_to:5,bracket:[8,19,22],branch:[3,5,6,7,13,19,21,25],branch_fals:19,branch_tru:19,breakpoint:8,bring:[6,8,19],bruijn:19,brutal:16,brzozowski:[19,21],brzozowskian:5,btree:[11,17],buck:11,bug:[0,8],build:[7,8,12,13,15,20,24],built:[12,19],bullet:23,bundl:[2,3,13],burgeon:8,c:[0,1,2,3,5,7,9,11,13,15,16,17],calculu:4,call:[1,2,5,8,10,11,13,16,19,23,24],caller:[11,19],can:[0,2,3,4,5,6,7,8,9,10,12,13,14,15,16,17,19,20,21,22,24,25],cancel:16,cannot:[18,19,22],captur:8,card:8,care:[6,24],carefulli:20,carri:[7,11],cartesian:4,catamorph:21,categor:[0,21],categori:[4,16],ccc:4,ccon:[3,11,18,19,25],cell:[13,19],certain:[8,24],certainli:11,cf:[7,9,12,13],chain:[3,16],chang:[2,10,11,15,19,20],charact:[5,20,24],chat:8,chatter:[0,19],check:[0,7,9,19,21],child:17,choic:[3,13],choos:10,chop:12,chose:5,cinf:11,circl:5,circuit:[4,15],cite_not:11,classmethod:[],claus:[3,19],clean:19,clear:[3,6,8],clear_stuff:11,cleav:[8,12,14],client:24,close:[0,1,4],clunki:[6,19],clv:16,cmp:[3,17,21],cmp_:3,code:[1,4,5,12,13,16,19,21,24,25],codireco:[7,9,15],collaps:13,collect:[4,5,7,8,19],combin:[0,3,6,7,8,9,12,15,16,17,20,21,23,24,25],combinatorjoytyp:19,come:[8,11,19],command:[8,11,19],comment:16,common:[2,6,16],compar:[3,4,5,15,19],comparison:[0,11],compat:16,compel:4,compil:[2,3,4,5,8,11,14,16,21,25],complement:5,complet:4,complex:[3,16,19,20,25],complic:19,compos:[5,25],composit:19,compostit:19,compound:11,comput:[2,4,5,6,8,12,15,16,19,25],con:[3,5,6,7,8,9,11,12,13,15,16,17,20,24,25],conal:[4,16],concat:[3,7,8,16,17,19,24],concat_:3,concaten:[0,5],concatin:[0,3,5,24],concern:16,conclus:21,concurr:2,cond:[3,11],condit:[3,8],condition:15,confer:19,conflict:[11,19],consecut:21,consid:[5,6,7,11,13,17,19,20],consist:[2,7,8,16,17],constant:11,constitu:13,constraint:15,construct:[0,15,16,19],consum:[15,16,19],contain:[0,2,3,5,7,8,13,15,19,22],content:19,context:2,conting:11,continu:[0,5,13,19,20],control:8,conveni:[4,16,19],convent:16,convers:[19,24],convert:[13,14,17,19,22,24],cool:11,coordin:[0,15],copi:[2,3,6,11,13,15,16,17,18,21],copyright:8,correspond:[4,16],could:[2,4,5,6,8,10,11,16,19,20],couldn:16,count:[3,19],counter:[6,19],coupl:17,cours:[6,11,19],cout:15,cover:19,cp:8,cpu:16,crack:11,crash:11,creat:[0,2,3,6,9,11,16,19],creativ:19,crude:[11,19,22],cruft:19,curent:25,current:[2,3,8,13,15,16,17,19,20,23,25],curri:5,custom:10,cycl:[6,7],cython:8,d010101:5,d0101:5,d01:5,d0:5,d10:5,d1:5,d:[2,3,5,11,13,14,16,17,18,19,20],d_compact:5,dai:8,data:[2,3,5,13],datastructur:[0,2,13,19,21,22,24],datatyp:24,ddididi:20,de:[19,20],deal:[0,5,11,16],dealt:19,debugg:19,decid:11,declar:19,decor:3,decoupl:13,decrement:[0,3],deduc:[6,19],deeper:0,deepli:4,def:[3,5,8,13,14,19,24],defaultdict:[5,19],defi:[],defin:[2,4,5,6,7,8,9,10,12,13,14,15,16,19,20,21],definit:[0,2,3,6,7,8,10,11,13,15,17,19,21,25],definitionwrapp:[11,13,17],defint:16,del:18,deleg:8,delet:21,deliber:19,demo:19,demonstr:4,depend:[3,11,13,16],deposit:17,depth:[19,25],dequot:13,der:11,deriv:[2,3,6,8,9,11,19,21],derv:5,describ:[4,5,11,13,16,17,19,22,24],descript:[6,8],descriptor:19,design:[2,3,11,16,21],desir:[8,17],destin:5,destruct:11,detail:[8,11,19],detect:[5,7,11,13,19],determin:21,develop:[0,7,8,19,21],diagram:6,dialect:1,dict:[1,3,5,19,23],dictionari:[0,1,3,8,19,21,23],did:19,differ:[0,4,6,9,11,12,13,16,24],differenti:4,difficult:19,difficulti:16,dig:[11,20],digit:6,digraph:5,dinfrirst:[8,15,19,25],dip:[0,3,6,7,8,9,11,12,13,14,15,16,17,19,21,25],dipd:[3,7,8,11,12,13,15,16,19,20,25],dipdd:[3,11],direco:21,direct:8,directli:[6,16,17,19,24],disappear:[2,5,19],discard:[3,7,9,11,13],disciplin:11,disenstacken:[3,8],disk:8,displac:2,displai:19,distiguish:19,distribut:16,ditch:11,div:[3,8,19,25],dive:17,divis:[11,19],divmod:[3,25],divmod_:[3,19],dnd:24,doc:[2,3,8,19],doc_from_stack_effect:18,docstr:19,document:[19,21,22,24],doe:[0,1,3,4,5,7,8,14,16,19,21,23,25],doesn:[6,10,11,15,16,17,19,24],domain:[4,19],don:[5,6,8,11,19],done:[2,6,8,10,19],dooooc:19,door:8,dot:[5,23],doubl:[5,6,8,19],doublecircl:5,down:[2,5,9,13,20,25],down_to_zero:8,dozen:8,dr:5,draft:[4,10],drag:24,dream:8,drive:[7,9],driven:6,driver:[5,7],drop:[3,11,24],ds:5,dudipd:8,due:19,dup:[3,6,7,8,9,11,12,13,15,16,18,20,24,25],dupd:[3,19,25],dupdd:[3,25],dupdip:[3,6,11,12,13,15],duplic:[3,11,13],durat:2,dure:[2,13],e:[2,3,5,7,8,10,11,14,16,18,19,20,23,24],each:[2,3,4,5,6,8,13,14,15,16,17,19,23,25],easi:[0,11,15,17,19,20],easier:[3,11,16],easili:4,eat:5,edit:21,ee:[11,19],effect:[2,3,5,8,16,20,21,25],effici:[7,14,20],efg:19,eh:19,either:[1,2,3,5,11,13,19],el:24,elabor:19,eleg:[0,5,8,11,16,21],element:[2,3],elif:19,elimin:[5,19],elliott:[4,16],els:[2,3,5,13,15,16,19],else_:19,embed:[4,11,20],emit:19,empti:[3,5,8,17,19,24,25],en:11,encapsul:8,enclos:8,encod:7,encount:19,end:[5,6,11,13,17,19,24],endless:7,enforc:[2,8],engend:8,enough:[5,8,13,23,25],enstacken:[7,8,19],enter:8,enter_guard:19,entir:24,entri:[3,20,23],enumer:19,epsilon:9,eq:[2,3,25],equal:[3,6,17,24],equat:[8,9],equival:16,er:[0,8],ergo:[5,11],err:[11,18],error:[8,19,22],essai:0,establish:19,et:[16,19],etc:[3,17,19,20,22],euler:21,euro:19,eval:[0,19],evalu:[1,2,3,8,9,11,12,13,14,16,17,19,23],event:16,eventu:[16,19],ever:19,everi:[1,7,16],everybodi:16,everyth:[3,5,11,12,16,19],evolv:10,examin:13,exampl:[3,5,6,19,21,22,24,25],exce:7,except:[1,5,8,11,18,19,22],execut:[0,1,2,3,8,13,14,16,17,19,20,24,25],exend:19,exercis:[5,11],exist:[4,11,19,24],expand:11,expect:[2,3,16,17,19,24],experi:[8,17],explain:19,explan:8,explor:[8,19],express:[0,1,2,3,4,11,13,14,15,19,20,21,23,24],expression_to_str:[19,24],extend:19,extra:[1,6,7],extract:[11,12,21],extrem:8,extrememli:8,f0:19,f1:[18,19,25],f2:[18,19,25],f3:[19,25],f:[2,3,5,6,7,9,13,15,16,19],f_g:19,f_in:19,f_out:19,f_python:19,facet:0,facil:8,fact:22,factor:[2,6,8,11,15,19],factori:[3,21],fail:[2,3,11,21,22],fail_fail:[],fairli:19,fake:5,fall:19,fals:[2,3,5,6,13,15,16,19],falsei:19,familiar:[0,15,24],far:[9,11,13,19,25],fascin:0,favorit:16,fear:[11,19],few:[6,8,9,12,16,19],fewer:[3,8],fg:19,fg_in:19,fg_out:19,fi:[18,19],fib:7,fib_gen:7,fibonacci:21,figur:[2,3,11,13,19],file:15,filter:11,fin:6,find:[2,3,5,6,7,16,17,19,21,25],finder:9,fine:[0,5,6,11,19,25],finite_state_machin:5,first:[3,5,7,8,9,11,12,13,14,17,20,21,24,25],first_two:[3,11,25],fit:[6,8],five:[6,8,21],fix:[2,3,5,13,19],fixm:[5,19],flag:[16,19],flatten:[8,17,19],flesh:5,flexibl:21,floatjoytyp:19,floatstarjoytyp:19,floor:3,floordiv:[3,6,25],flow:8,fn:19,fo:[18,19],follow:[0,2,3,5,8,10,13,16,17,19,20],foo:[8,10,11,16,19],foo_ii:10,fork:16,form:[2,3,4,5,6,7,13,17,19,21,24],forman:8,format:[18,19,21,23],formula:[0,6,21],forth:[8,19],forum:0,forward:19,found:8,four:[0,2,3,6,7,8,11,15,21],fourteen:6,fourth:[2,3,11,13,25],fr:5,frac:[9,12],fractal:8,fraction0:8,fraction:[2,8],frame:13,framework:8,free:[4,8,11],freeli:2,from:[0,1,2,3,5,6,7,8,9,11,12,14,15,16,17,18,19,20,21,24],from_:5,from_index:24,front:[2,3,13],frozenset:5,fulfil:24,fulin:[],full:6,fun:[5,21],func:19,functionjoytyp:19,functionwrapp:3,functool:5,fundament:[0,21],funtion:11,further:[9,19,21],futur:16,g:[2,3,5,7,8,9,10,11,13,14,16,18,19,20,23,24],g_in:19,g_out:19,garbag:8,gari:11,gcd2:3,gcd:[3,8],ge:[2,3,25],gener:[0,2,4,16,19,21,24,25],generated_librari:3,genrec:[3,8,11,13,16,17,19],geometr:6,get:[2,4,5,6,7,8,12,13,19,21],getch:5,getitem:3,getrecursionlimit:[],getsourc:8,ghc:4,gi:19,give:[4,6,11,13,15,17,19,24],given:[2,3,6,7,9,11,15,16,19,20,21,24],global:[18,19],glue:8,go:[5,6,11,12,13,15,16,17,19,20,23],goe:25,good:[6,11,19],grab:[3,19],grammar:22,grand:8,graph:[5,16],graphic:5,graphviz:5,great:[0,8,19,21],greater:24,grind:19,group:0,grow:5,gsra:9,gt:[2,3,25],guard:[11,19],h:[5,13,19],ha:[0,2,3,5,7,8,9,10,11,13,16,19,20,24],had:[5,6,20],haiku:8,half:[6,19,20],hallmark:16,hand:[5,8,14,19,21],handi:[9,19],handl:[11,19,24,25],happen:[8,19],happi:5,hard:[5,19,20],hardwar:4,hasattr:19,hash:19,haskel:4,have:[2,3,5,6,7,8,9,10,13,14,15,16,19,20,21,24,25],he:[4,9],head:24,heh:19,help:[0,3,8,11,13,15,19],help_:3,helper:5,herd:8,here:[0,5,6,7,11,15,17,19,20,25],hg:25,hide:11,hierarchi:19,higher:[5,8,11,19],highli:8,hij:5,histori:[19,23],hit:5,hmm:[5,11],hoist:3,hold:[6,19],hood:11,hope:[0,6,8,21],hopefulli:13,host:21,how:[0,4,5,9,11,13,15,19,20,21],howev:[13,14,16,19],html:[2,3,7,12,13,21],http:[11,25],huet:20,huge:11,hugh:[9,17],human:8,hybrid:[15,25],hylomorph:21,hypothet:2,i0:19,i1:[18,19,25],i2:[18,19,25],i3:[19,25],i:[0,3,6,7,8,9,13,14,15,16,17,20,21,23,24,25],id:[3,19],id_:3,idea:[4,6,8,19],ident:[3,5,13,19,25],if_not_empti:11,ift:[0,3,11,13,15,17,19,25],ignor:[1,3,11,19],ii:[0,3,15,21],iii:21,illustr:[5,13],imagin:[5,16,20],imap:19,imit:[5,17],immedi:[5,13],immut:[5,8,11],imper:13,implement:[0,1,2,4,8,10,11,13,14,16,21,25],implementaion:16,implicit:8,improv:19,includ:[4,11,16,17,19,25],inclus:6,incom:24,incompat:10,incorpor:12,increas:6,increment:[0,3,4,6,10,16],index:[0,8,19,24],indexerror:24,indic:[16,17,19,24,25],ineffici:19,infer:[0,18],inferenc:25,info:[18,19],inform:[3,5,19,25],infra:[3,7,8,11,12,14,15,16,17,19,21,25],infrastructur:3,initi:[2,3,5,8,9,11,19],inlin:11,inner:19,inproceed:19,input:[1,9,16,18,19],input_:5,inscrib:3,inscribe_:3,insert:[19,24],insight:13,inspect:8,inspect_stack:19,instal:0,instanc:19,instanti:[4,23],instead:[5,6,7,11,13,15,19,20,24,25],instruct:5,integ:[0,2,3,8,15,17,19,22],integr:3,intend:[0,8],interact:[8,21],interest:[0,6,11,19,21],interfer:16,interlud:21,intermedi:13,intern:[0,19,23,24],interp:1,interpret:[0,4,10,14,22,23,25],interrupt:8,intersect:5,interspers:16,interv:[4,6],intjoytyp:19,introduc:10,introduct:0,intstarjoytyp:19,intuit:19,invari:3,invent:19,involv:19,ipf:8,ipython:19,isinst:[5,19],isn:[3,5,11,20],issubclass:19,item:[2,3,8,11,13,16,17,19,21,24],iter:[1,3,5,8,13,16,17,19,21,24],iter_stack:[14,24],iteritem:[5,19],itertool:[5,19],its:[0,1,2,3,4,6,8,11,13,15,16,17,19,24],itself:[0,2,8,11,16,19],iv:21,j05cmp:[2,3,13],j:[2,5,6,7,9,11,12,13,14,15,17,19,20],jaanu:19,jmp:5,job:[16,21],john:[9,17],joi:[2,4,10,11,12,14,16,18],join:[5,19],joypi:[20,25],joytypeerror:18,jp:[7,12],js:8,jump:5,jump_from:5,junk:19,jupyt:21,just:[0,2,3,5,7,8,10,11,13,15,16,17,19,20,23],juxtaposit:16,k:[6,11,17,19],keep:[5,11,12,16,19,20],kei:[5,17,21],kevin:0,key_n:11,keyerror:[5,11,19],kind:[0,2,4,8,11,13,15,17,19,25],kinda:19,kleen:[17,19],kleenestar:19,kleffner:19,know:[6,11,19],knowledg:19,known:[4,16],kstar:5,l:[3,5,11,19],l_kei:11,l_left:11,l_right:11,l_valu:11,la:0,label:[5,19],lambda:[4,5,19,24],languag:[3,4,5,8,10,11,14,19,24],larg:[5,19],larger:21,largest:3,last:[6,11,13,19],lastli:7,later:[5,8,15,17,19],law:2,layout:[0,15],lazi:19,lazili:9,lcm:6,le:[2,3,25],lead:[5,8,19],leaf:11,lean:8,learn:0,least:[2,6,13,19,24],least_fract:8,leav:[3,6,15,16],left:[5,8,12,13,16,17,19,20,23,24],leftov:13,legend:5,legibl:[0,15],len:[5,19],length:[3,6,24],lens:13,less:[6,7,8,13,19,24],let:[7,9,11,12,13,15,17,19,20,21],letter:19,level:[4,5,11,18,19],librari:[0,5,14],like:[0,2,3,5,6,8,15,16,17,19,21,22,23,25],limit:[19,25],line:[8,11,12,19,23,25],linear:24,link:[0,5,19],linux:0,list:[0,3,5,6,8,9,11,16,17,19,20,23],list_to_stack:[19,24],liter:[1,11,17,19,20,22,24],literatur:19,littl:[0,5,7,11,15,16,19,21],live:21,lk:17,lkei:17,ll:[5,6,7,8,13,15,17,19,20],load:[6,8],local:19,locat:2,locu:23,log:[18,19],log_2:11,logic:[0,6,15,21],london:24,longer:[11,19],look:[1,5,7,8,9,11,12,15,16,19],lookup:8,loop:[0,1,3,5,6,19,21,25],lose:19,lot:[5,8,11,19,20],love:6,low:[4,5],lower:6,lowercas:[5,19],lowest:11,lr:5,lshift:[3,25],lt:[2,3,25],m:[0,5,6,8,11,15,16,17,19],machin:[0,21],machineri:[11,19],macro:8,made:[0,8,16,19,20],magic:19,mai:[2,13,16,25],mail:0,main:[0,3,8,12,15,16,19,20],mainloop:10,maintain:20,major:10,make:[2,3,4,6,8,11,13,14,15,16,17,19,20,21],make_gener:[9,15],make_graph:5,manfr:[0,2,3,4,13,24],mani:[0,5,8,19],manipul:19,manner:12,map:[1,3,5,6,8,10,13,17,19,23],map_:3,marker:8,mask:[6,7,15],match:[0,1,19,21],materi:0,math:[0,8,9,11,12,19],mathemat:8,matter:[6,9,11,17],max:3,max_:3,maximum:3,mayb:[11,19],mc:19,me:[8,17,19],mean:[4,6,8,9,11,13,17,19,24],meant:[8,11,13,17,24],mem:5,member:[2,3,13,24],memo:5,mental:8,mention:2,mercuri:[],mess:19,messag:[18,19],meta:[8,11,14],meta_compos:19,method:[0,8,19,21,23],midpoint:6,might:[0,4,5,7,11,15,19],mike:11,million:7,min:3,min_:3,mind:19,minimum:3,minor:11,minu:3,mirror:0,miscellan:0,mismatch:19,mix:[8,19],mod:3,mode:19,model:[4,8],modern:0,modif:[7,19],modifi:[8,11,20],modul:[0,1,3,8,19,22],modulo:19,modulu:[3,8,25],moment:19,month:8,more:[0,3,4,5,6,7,8,9,13,14,16,17,19,22,24,25],most:[5,19,25],mostli:0,move:[5,11],movement:2,ms:21,much:[5,6,7,11,13,19,24],muck:11,mul:[3,8,12,18,20,23,25],multi:[],multipl:[21,25],multipli:3,must:[2,3,6,10,13,16,17,19,22],my:[0,6,8,16],myself:19,n0:19,n10001:19,n10002:19,n10003:19,n1001:19,n1002:19,n1003:19,n1:[19,25],n2:[19,25],n3:[19,25],n4:[19,25],n:[2,3,5,6,8,9,11,14,15,17,19,20,24],name:[1,3,5,8,10,11,13,19,20,21,22,23,24,25],narr:19,natur:[5,6,7,11,19],navig:20,ne:[3,25],nearli:19,neat:11,neato:19,necessarili:19,need:[2,3,6,7,9,10,11,13,15,16,19,24],neg:[3,12,25],neither:[2,16,19],ness:5,nest:[3,8,11,20],net:25,network:8,never:[5,10,13],new_def:19,new_f:19,new_fo:19,new_kei:11,new_valu:11,newton:[0,21],next:[0,5,6,15,16,17,19,25],nice:[0,5,13,24],niether:[],nk:6,nm:5,node:[5,17,21],node_kei:11,node_valu:11,non:[5,17,19,22],none:[1,19],nope:17,nor:5,normal:16,not_:3,notat:[0,8,11,15],note:[2,5,6,9,11,13,16,19,24],notebook:[6,7,8,19,20,21],notebook_preambl:[2,6,7,9,11,12,13,14,15,17,19,20],noth:[2,11,16],notic:6,now:[3,5,6,7,8,13,14,17,19,21],ns:19,nth:[3,24],nullari:[8,11,15,16,19,25],number:[0,1,2,3,6,7,9,15,16,24,25],numberjoytyp:19,numberstarjoytyp:19,numer:19,o:[5,7,11,19],object:[5,19,22,24],observ:6,obviou:7,obvious:19,occur:11,occurr:24,odd:[6,7],off:[2,3,6,7,12,15,19,20],often:[5,16],oh:11,ok:19,old:[0,2,14],old_k:11,old_kei:11,old_valu:11,omg:[],omit:[13,19,22],onc:[3,5,10,11],one:[0,2,3,5,6,7,11,13,15,16,17,19,23,24,25],ones:[5,7,19],onli:[2,3,5,6,11,13,15,16,19,20,24],onto:[1,2,3,8,13,24],open:[8,19],oper:[0,3,5,8,11,13,21,24],oppos:19,optim:11,option:[1,8,11,19,24],or_:3,orchestr:16,order:[0,2,3,8,13,16,18,19,21,24],org:[0,11],origin:[0,1,2,3,11,20,21],osdn:25,other:[0,2,3,4,5,8,11,13,15,17,19,24],otherwis:[3,5,6,7,11,17,19],our:[5,6,7,8,9,13,15,17,19],out:[2,3,4,6,7,8,9,11,12,13,15,16,19,20,21],outcom:17,outlin:5,output:[1,5,9,13,16,18,19,25],outsid:4,over:[3,4,6,7,8,9,11,12,16,17,19,21,25],overhaul:19,overview:[3,19],own:[11,19],p:[2,3,6,11,13,16],pack:24,packag:[0,8],page:[0,11,19,24],pair:[0,2,3,6,7,11,15,19],palidrom:6,palindrom:6,pam:8,paper:[4,8,13,16,20],paradigm:21,parallel:[2,21],param:[],paramet:[1,2,3,13,14,22,23,24],parameter:21,paramorph:13,parenthes:[11,24],pari:24,pariti:7,pars:[0,5,8],parse_definit:[],parseerror:22,parser:[0,18,19],part:[2,3,9,13,17,21],partial:[5,19],particular:20,pass:[0,5,11,19,23],patch:5,path:[5,15,19,21],pattern:[5,6,16,17,21],pe1:[6,7],pe2:7,pearl:20,pend:[3,8,13,19,20,23],peopl:21,per:[8,17],perfectli:16,perform:[5,16,19],perhap:7,period:8,permit:[16,19,24],permut:19,persist:11,phase:2,phi:5,phrase:15,pick:[3,6,7,16,24],pickl:8,pictur:11,piec:[13,21],pip:0,place:[3,6,8,19],plai:0,plu:3,plug:[7,13,17],pm:[3,12,19,25],point:[4,5,8,11,13,15,16],pointless:2,pool:16,pop:[0,3,5,6,7,8,11,13,14,15,17,18,24,25],popd:[3,8,9,11,14,16,19,25],popdd:[3,7,12,19,25],popop:[3,6,7,8,9,11,17,19,25],popopd:[3,25],popopdd:[3,25],posit:[3,6,8,13],possibilit:11,possibl:[11,17,19,21],post:8,poswrd:19,potenti:16,pow:[3,25],power:[8,19],pprint:5,pragmat:6,preambl:9,preceed:16,precis:[0,1],pred:[3,19,25],predecessor:3,predic:[2,3,5,7,13,16],prefix:[19,23],preliminari:5,present:19,preserv:[4,17],pretti:[9,11,12,16,17,19,23,24],pretty_print:0,previou:[8,16],prime:9,primit:[2,3,19,21],primrec:[3,7,8,13],print:[0,1,2,3,5,18,19,23,24],probabl:[7,8,11,19],problem:[8,15,19,21],proc_curr:11,proc_left:11,proc_right:11,proce:[6,25],process:[5,8,17,19,23],produc:[3,6,11,13,17,19],product:[5,7,8,18,19],program:[0,2,3,7,8,9,11,13,15,16,19,20],programm:[16,19],progress:16,project:[21,25],prolog:19,promis:16,prompt:8,proper:[2,3,13,16,25],properti:0,provid:[0,4,8,16,19,25],pseudo:15,pun:[0,8],punctuat:19,pure:[0,5],puriti:8,purpos:8,push:[2,3,8,13,20,24],put:[1,2,7,8,16,19,21,24],pypi:0,python3:8,python:[0,2,3,5,11,13,16,20,21,22,24,25],q:[2,3,11,13,16,19,20],quadrat:[0,21],quasi:15,queri:[11,17],query_kei:17,queu:13,quit:[0,17],quot:[0,3,7,8,11,12,13,15,16,17,19,20,23],quotat:[2,3,13,24],quotient:3,r0:[9,11,17],r1:[2,3,9,11,13,17],r2:[2,3,13],r:[2,3,5,11,13,19],r_kei:11,r_left:11,r_right:11,r_valu:11,rais:[5,11,19,22,24],rang:[5,8,19],range_revers:13,range_to_zero:8,ranger:13,ranger_revers:13,rankdir:5,raphson:9,rather:[6,8,13,15,17],ratio:8,re:[0,6,7,8,9,14,15,19,21,22],reach:[5,6,7,13],read:[0,1,6,7,11,19,20],readabl:14,reader:[5,11],readi:19,readm:15,real:11,realiz:[4,11,15],rearrang:[2,11,19,24],reason:[6,8,16,19],rebuild:[17,20],rec1:[2,3,13],rec2:[2,3,13],recent:19,recogn:22,recombin:16,record:[8,23],recur:[3,13,19],recurs:[0,2,3,5,7,8,9,16,19,21,24],recus:8,redefin:21,redistribut:[3,8],redo:5,reduc:[2,19],redund:24,refactor:[8,10],refer:[0,2],referenti:16,reflect:16,regard:16,region:15,regist:2,regular:[19,21,22],reifi:18,reimplement:[16,21],rel:24,relat:[5,19],releas:10,rem:3,remain:[2,8,10,19],remaind:[3,9],rememb:5,remind:19,remot:24,remov:[3,11,19,24,25],render:21,repeat:6,repeatedli:6,repetit:5,repl:[0,1],replac:[0,2,3,7,12,13,16,17,19,20,21,24],repositori:0,repr:[5,19],repres:[2,8,11,16,22,23],represent:24,reprod:7,repurpos:19,requir:[15,16,19,24],research:19,resembl:8,resolut:16,resourc:16,respect:[5,6,16],rest:[3,6,7,8,11,13,15,20,21,24,25],rest_two:11,restart:[],restor:2,result:[1,2,3,5,6,11,12,13,16,17,19,20,24],resum:8,retir:2,retri:8,reus:[11,19,24],revers:[3,6,7,13,19,20,21,24],revisit:19,rewrit:[3,8,15,19],rewritten:8,rid:11,right:[7,8,12,17,19,21,23,24],rightest:11,rightmost:6,rigor:16,risk:19,rk:17,rkei:17,rob:19,role:24,roll:[3,9,11,17],roll_dn:19,rolldown:[3,18,19,25],rollup:[3,19,25],root:[3,9,12],rough:15,round:[3,19],row:5,rrest:[3,18,19,25],rshift:[3,25],rtype:[],rule:[16,21],run:[0,1,3,6,8,9,11,12,13,15,16,17,19,20],runtim:16,runtimeerror:[],s0:19,s1:[18,19,25],s2:[18,19],s3:19,s4:19,s5:19,s:[0,1,2,3,4,7,8,10,12,13,14,15,16,17,18,20,21,23,24,25],sai:[5,7,11,12,15,17,19],same:[2,4,6,11,16,19,24],sandwich:[2,3,13],save:[2,5,6,8],scan:[],scanner:[8,22],scenario:20,scm:25,scope:[7,11],script:1,se:19,search:[0,11],sec:19,second:[3,8,11,13,15,17,24,25],section:13,see:[0,5,7,8,9,10,12,13,14,15,19,20,23],seem:[0,6,8,15,17,19,25],seen:[19,20],select:3,self:[5,16,19],semant:[2,3,8,10,11,16,19],semi:8,send:8,sens:[0,2,6,19,20],separ:[8,16,19,22],seq:19,sequenc:[0,1,2,3,6,8,11,13,14,20,21,22,25],sequence_to_stack:19,seri:[6,7,11,15,20],set:[2,3,5,13,19,21,24],seven:[6,7],sever:[0,4,8,13],shape:[5,16],share:[3,8],shelf:2,shew:5,shift:[6,7],shorter:21,shorthand:11,should:[2,3,5,6,11,13,16,19],shouldn:8,show:[4,15,16,19,20],shunt:[3,20],side:[5,11,18,19,25],sign:[],signatur:25,signifi:[8,11],similar:[11,15,17,19],simon:8,simpl:[1,5,8,13,15,24,25],simplefunctionwrapp:[3,14,19],simpler:17,simplest:[19,21],simpli:4,simplifi:[6,11,20],sinc:[2,6,11,15,19],singl:[3,7,8,14,15,16,19,22,25],singleton:5,situ:11,situat:11,six:[6,7,8],sixti:[6,7],size:[5,8,21],skeptic:8,skip:19,slight:9,slightli:[11,13,19],smallest:3,smart:11,sn:19,so:[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19,20,24,25],softwar:8,solei:2,solut:[6,7],solvabl:8,some:[0,2,3,5,7,8,11,13,15,16,17,19,21,24,25],somehow:[11,19],someth:[2,10,11,19],sometim:11,somewher:[11,21],sort:[3,5,11,16,19],sort_:3,sourc:[0,1,3,19,21,22,23,24],space:[6,23],span:6,spawn:19,special:[7,11,21],specif:[0,4],specifi:[11,16],speed:14,spell:[5,17],sphinx:[21,24],spiral:[0,21],spiral_next:15,spirit:[0,1,17],split:[5,19],sqr:[3,8,9,12,20],sqrt:[3,9,19,25],squar:[0,3,9,19,21,22],square_spir:[],ss:19,stack:[0,1,3,6,7,9,11,12,13,14,15,16,17,18,20,21,22,23,25],stack_effect:19,stack_effect_com:19,stack_to_str:[18,24],stacki:19,stackjoytyp:19,stacklistbox:24,stackoverflow:15,stackstarjoytyp:19,stage:17,stai:[0,1],stand:[4,5],standard:[8,11],star:[17,19],stare:11,start:[5,6,7,8,9,11,13,17,19,25],state:[8,21],state_nam:5,statement:[3,5,15],stdout:[18,19],step:[3,6,8,11,14,19,20,21],stepper:15,stevan:24,still:[5,11,19],stop:11,stopiter:5,storag:[6,11],store:[6,13,19],stori:13,str:[1,5,19,22,23,24],straightforward:[5,7,9,15,19,21],stream:[6,18,19],stretch:11,string:[1,2,3,8,19,20,21,22,23,24],stringi:5,structur:[8,16,17,19,20,21,24],stuck:5,studi:5,stuff:[11,19],stuncon:[3,25],stununcon:[3,25],style:[0,4,19],sub:[3,10,16,25],subclass:8,subject:[16,20],subsequ:16,subset:[19,25],substitut:[5,11,19],subtract:6,subtyp:21,succ:[3,19,25],succe:19,success:9,suck:19,suffic:19,suffici:11,suffix:19,suggest:[4,5,11],suitabl:[1,3,4,6],sum:[3,7,8,12,13,14,17],sum_:[3,19],summand:6,sumtre:17,suppli:[11,22],support:[8,19,23,24],sure:16,suspect:2,svg:[],swaack:[3,12,14,15,19,20,25],swap:[3,6,7,8,9,11,13,14,15,16,17,18,20,25],swon:[3,7,8,13,17,19,20,25],swoncat:[7,8,9,13,17],swuncon:13,sy:[18,19],sym:5,symbol:[1,2,3,5,16,19,20,21,22,23],symboljoytyp:19,symmetr:[6,11,15],symmetri:[5,15],syntact:8,syntax:[8,24],system:[8,11,16],t0:3,t1:3,t:[2,3,5,6,8,10,11,13,15,16,19,20,24],tabl:[5,19],tag:[5,19,25],tail:[9,11,19,21,24],tailrec:[3,9],take:[3,5,6,8,9,11,13,15,16,19,24],talk:[8,11,19,24],target:20,tast:4,tbd:8,te:11,tear:13,technic:2,techniqu:[4,20],technolog:2,temporari:20,ten:6,term:[1,2,5,8,9,13,16,19,21,22,24,25],termin:[2,3,5,13],ternari:8,test:[2,3,13],text:[0,1,19],text_to_express:[8,18,22],textual:8,than:[0,3,5,6,7,8,9,13,16,17,19,24,25],thei:[2,5,6,7,8,11,13,15,16,19,20,22,24],them:[0,2,5,6,7,11,13,15,16,19,20,21,24,25],themselv:[16,19],theori:[2,3,13,16],therefor:7,thi:[0,1,2,3,4,5,6,7,8,9,12,13,15,16,17,19,20,21,22,23,24,25],thing:[2,7,11,13,16,19,20,22,24,25],think:[2,6,8,11,13,16,17,19],third:[3,7,8,11,25],thirti:6,those:[2,3,5,11,13,15,19,21,24,25],though:[6,16],thought:[8,16],thousand:6,thread:[2,16],three:[2,3,5,6,8,11,12,15,17,19,21],through:[1,6,8,17,19,20,24,25],thun:[2,3,4,10,13,16,24],thunder:8,thunk:16,time:[3,5,6,8,9,11,13,15,16,19,20],titl:19,to_check:5,to_index:24,to_set:11,todai:8,todo:[8,22],togeth:[7,8,16,19,21],token:22,toler:21,too:[5,13,19],tool:[8,19],tooo:19,top:[2,3,8,13,19,23,24],total:6,tower:19,trace:[0,8,12,13,15,20,21,24],traceback:19,traceprint:23,track:[12,19,20],tracker:0,transform:4,transit:5,translat:[4,12,19,21],trap:5,travers:[0,21],treasur:0,treat:[0,2,3,13,19,21],treatment:7,tree:[0,8,21],treegrind:21,treestep:[0,21],tri:6,triangl:16,triangular_numb:13,trick:[6,19],tricki:19,trobe:0,trove:0,truediv:25,truth:24,truthi:[3,8,16,19],ts:17,tuck:[3,8,19,25],tupl:[3,5,8,19,24],turn:[2,3,5,19,21],twice:[11,13],two:[0,2,3,6,8,9,11,12,13,15,16,17,18,19,20,21,24,25],txt:[],type:[0,1,4,8,11,13,16,21,22,23,24],typeerror:19,typeless:19,typic:[2,3,12,13],u:[18,19],uh:19,ui:8,uk:[],ulam:[0,15],unari:8,unarybuiltinwrapp:3,unbalanc:[11,22],unbound:25,unchang:[3,11],uncompil:19,uncon:[3,7,8,11,13,17,20,25],under:[2,3,8,11],underli:[5,16,19],underscor:19,understand:[0,11],undistinguish:11,undocu:8,unfinish:5,unfortun:24,unicod:19,unif:[19,21],unifi:18,union:5,uniqu:[3,5,11,19],unit:[3,8,13,16,25],univers:[0,8,16,19],unknownsymbolerror:1,unlik:16,unnecessari:21,unnecesssari:19,unpack:[2,3,11,24],unpair:6,unquot:[8,15,17],unread:[0,15],unrol:5,unstack:19,unswon:[3,25],untangl:13,until:[5,7,16],unus:6,unusu:11,unwrap:5,up:[1,2,3,6,7,8,11,13,14,15,16,19,20,24],updat:[0,18,21,25],uppercas:5,upward:16,us:[0,1,2,3,4,5,6,8,9,10,11,12,13,14,15,16,17,20,21,22,24,25],usag:8,user:17,usual:[0,2,13],util:[0,3,14,18,19],uu:19,v0:25,v:[2,6,7,9,11,12,13,14,15,17,20,21],valid:19,valu:[0,1,2,3,6,8,9,12,13,14,15,16,17,19,21,22,24,25],value_n:11,valueerror:[5,19,24],variabl:[19,21,24],variant:11,variat:[13,16,21],varieti:[4,8],variou:0,ve:[11,15,19],vector:[],vener:24,verbos:4,veri:[0,1,4,5,8,11,15,24],versa:[2,19],version:[0,1,2,5,7,10,17,20,21],vi:21,via:8,vice:[2,19],view:[11,21],viewer:[1,8,10,23],vii:21,visibl:19,von:[0,2,3,4,13,24],vs:19,vv:19,w:[3,11,13,17,19,24],wa:[2,6,8,11,15,16,19,24],waaaai:5,wai:[0,2,3,4,5,6,8,13,14,15,16,19],wait:16,want:[2,6,7,9,11,13,19],warranti:[3,8],wash:8,wast:8,we:[2,5,6,7,8,9,10,12,13,14,15,16,19,20,21,24],web:24,websit:[0,6],welcom:8,well:[0,4,8,9,11,19,22],went:19,were:[8,19,20],what:[2,3,4,5,8,11,13,16,17,19,23,24],whatev:[2,3,13,17,24],when:[6,7,8,11,13,16,19,20,22,24,25],where:[2,3,5,8,11,13,15,19,21,24],whether:[3,13],which:[0,1,3,5,6,8,9,11,15,16,17,19,20,22,24,25],whole:[2,3,6,13,17,19],whose:[7,24],why:[9,16,17],wiki:11,wikipedia:[0,11,20],wildli:8,wind:8,wire:13,within:[8,11,14,21],without:[2,8,11,12,15,16,19],won:[11,19,24],word:[0,3,6,8,13,20,24],work:[0,3,5,6,7,8,9,11,12,13,15,16,17,20,21,24,25],worker:16,worri:16,worth:6,would:[2,6,7,8,9,11,13,16,19,20,24],wrap:[3,8],wrapper:19,write:[4,5,9,11,13,15,16,17,19,20,21,24],written:[0,1,9,11,14,19,24],wrong:2,wrote:19,x:[0,3,5,6,8,9,16,20,21],xor:3,xrang:19,y:[2,3,5,15,16],yang:19,yeah:16,year:[8,19],yet:[11,16,19,20],yield:[2,3,13,19,24],yin:21,you:[0,2,3,5,6,7,8,10,11,12,13,14,15,16,17,19,20,23,24,25],your:[2,3,8,13,19],yourself:[5,8,11],z:[3,5,16,19,21],zero:[3,5,11,13,16,17,19,22,24],zerodivisionerror:19,zip:[3,5,6,19],zip_:3,zipper:[0,21],zstr:20},titles:["Thun 0.4.1 Documentation","Joy Interpreter","Functions Grouped by, er, Function with Examples","Function Reference","Categorical Programming","\u2202RE","Developing a Program in Joy","Using x to Generate Values","Thun: Joy in Python","Newton\u2019s method","No Updates","Treating Trees I: Ordered Binary Trees","Quadratic formula","Recursion Combinators","Replacing Functions in the Dictionary","Square Spiral Example Joy Code","The Four Fundamental Operations of Definite Action","Treating Trees II: treestep","Type Checking","The Blissful Elegance of Typing Joy","Traversing Datastructures with Zippers","Essays about Programming in Joy","Parsing Text into Joy Expressions","Tracing Joy Execution","Stack or Quote or Sequence or List\u2026","Type Inference of Joy Expressions"],titleterms:{"0":[0,13],"01":5,"1":[0,13],"11":5,"111":5,"2":[7,12,19],"2a":12,"3":[6,19],"4":[0,12,19],"466":7,"5":6,"\u03bb":5,"\u03d5":5,"boolean":15,"case":[9,11],"do":17,"function":[2,3,5,8,9,11,13,14,16,17,19],"long":14,"new":11,"p\u00f6ial":19,"try":5,"void":2,"while":[2,16],A:[5,6,7,9,11,14],If:11,In:[11,17],No:[5,10],Not:15,One:[7,11],The:[6,8,11,13,15,16,17,19],There:8,With:[5,17],about:21,action:16,ad:11,add:[2,11],address:20,al:13,alphabet:5,altern:17,an:[6,7,8,11,13,18,19,20],ana:13,analysi:6,anamorph:[2,13],app1:2,app2:2,app3:2,appendix:[11,13,19],appli:16,approxim:9,ar:11,argument:19,auto:3,averag:2,b:[2,12],base:[9,11],binari:[2,11,17],bliss:19,both:11,branch:[2,11,15,16],brzozowski:5,c:[12,19],can:11,cata:13,catamorph:13,categor:4,chatter:2,check:18,child:11,choic:2,clear:2,cleav:[2,16],cmp:11,code:[0,8,11,15],combin:[2,11,13,19],comment:19,compact:5,compar:11,comparison:2,compil:[7,19],compile_:19,compos:19,comput:9,con:[2,19],concat:2,conclus:[13,15,19],consecut:9,continu:8,current:11,datastructur:[5,8,11,20],deal:19,decrement:15,defin:[11,17],definit:[12,16],delabel:19,delet:11,deriv:[5,12,13,17],design:13,determin:20,develop:6,diagram:5,dialect:0,dictionari:14,dip:[2,20],dipd:2,dipdd:2,direco:7,disenstacken:2,distinguish:19,div:2,doc_from_stack_effect:19,document:0,doe:11,down_to_zero:2,drive:5,drop:2,dup:[2,19],dupd:2,dupdip:2,e:17,effect:19,eleg:19,els:11,empti:11,enstacken:2,equal:11,er:2,essai:21,et:13,euler:[6,7],eval:8,even:7,exampl:[0,2,8,11,13,15,17,18],execut:23,explor:5,express:[5,8,22,25],extract:17,f:11,factori:13,fail:18,fibonacci:7,filter:6,find:[9,11,13],finish:16,finit:5,first:[2,6,15,16,19],five:7,flatten:2,flexibl:17,floordiv:2,form:15,formula:12,found:11,four:[13,16],from:13,fsm:5,fulmin:16,fun:13,fundament:16,further:6,gcd:2,gener:[3,5,6,7,9,13,15],genrec:2,get:[11,17],getitem:2,given:[13,17],greater:11,group:2,h1:13,h2:13,h3:13,h4:13,handl:16,have:[11,17],help:2,highest:11,host:0,how:[6,7],hybrid:19,hylo:13,hylomorph:13,i:[2,5,11,19],identifi:19,ift:[2,16],ii:[17,19],iii:19,implement:[5,19],increment:15,indic:0,infer:[19,25],inferenc:19,inform:0,infra:[2,20],integ:[6,13],interest:7,interlud:11,intern:22,interpret:[1,8,19],item:20,iter:[6,11],iv:19,joi:[0,1,3,6,8,13,15,19,20,21,22,23,24,25],join:16,just:6,kei:11,kind:16,languag:0,larger:5,least_fract:2,left:11,less:11,let:[5,6],letter:5,librari:[3,8,19],like:11,list:[2,13,24],literari:8,littl:6,logic:[2,19],loop:[2,8,16],lower:11,lshift:2,machin:5,make:[7,9],mani:6,map:[2,16],match:5,math:2,memoiz:5,method:9,min:2,miscellan:2,mod:2,modifi:19,modulu:2,more:11,most:11,mul:[2,19],multipl:[6,7,19],must:11,n:13,name:12,ne:2,neg:[2,15],newton:9,next:9,node:11,non:11,now:11,nullari:2,nulli:5,number:[13,19],one:8,onli:8,oper:16,order:[11,17],origin:15,osdn:0,other:16,our:11,out:5,over:2,p:17,pack:6,pam:[2,16],para:13,paradigm:19,parallel:16,parameter:[11,17],pars:[2,22],parser:[8,22],part:19,pass:8,path:20,pattern:13,per:11,piec:15,pop:[2,19],popd:2,popop:2,pow:2,power:7,pred:2,predic:[6,9,11,15,17],pretty_print:23,primit:13,primrec:2,print:8,problem:[6,7],process:11,product:2,program:[4,6,12,17,21],progress:19,project:[0,6,7],pure:8,put:[11,12,15,17],python:[8,14,19],quadrat:12,quick:0,quot:[2,24],rang:[2,6,13],range_to_zero:2,re:[5,11],read:8,recur:[9,11],recurs:[11,13,17],redefin:[11,17],refactor:[6,11],refer:3,regular:[5,8],reimplement:17,relabel:19,rem:2,remaind:2,remov:2,render:6,repl:8,replac:[11,14],repres:[5,19],represent:5,reset:7,rest:[2,19],revers:[2,5,18],right:[11,20],rightmost:11,roll:[2,19],rolldown:2,rollup:2,rshift:2,rule:[5,19],run:[2,7],s:[5,6,9,11,19],second:[2,19],select:2,sequenc:[7,16,19,24],set:[9,11],shorter:14,should:8,shunt:2,simpl:19,simplest:6,size:[2,14],sourc:11,special:[13,19],spiral:15,sqr:[2,19],sqrt:[2,12],squar:15,stack:[2,8,19,24],start:0,state:5,step:[2,13,17],straightforward:12,stream:5,string:5,structur:11,style:8,sub:[2,11],subtyp:19,succ:2,sum:[2,6],swaack:2,swap:[2,19],swon:2,swoncat:2,symbol:[8,13],t:17,tabl:0,tail:13,take:2,term:[6,7,17],ternari:2,text:22,than:11,them:12,thi:11,third:[2,19],three:7,thun:[0,8],time:[2,7],togeth:[11,12,15,17],token:8,toler:9,trace:[14,23],traceprint:8,trampolin:5,translat:15,travers:[11,17,20],treat:[11,17],tree:[11,17,20],treegrind:17,treestep:17,triangular:13,truediv:2,truthi:2,tuck:2,turn:15,two:[5,7],type:[18,19,25],unari:2,unbound:19,uncon:[2,19],unif:18,unifi:19,unit:2,unnecessari:6,unquot:2,unstack:2,up:9,updat:[10,19],us:[7,19],util:[23,24,25],v:19,valu:[7,11],variabl:12,variat:7,version:[6,11,14,19],vi:19,view:8,vii:19,we:[11,17],which:13,within:9,word:2,work:[18,19],write:12,x:[2,7,15],xor:2,yin:19,z:20,zero:7,zip:2,zipper:20}}) \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/stack.html b/docs/sphinx_docs/_build/html/stack.html deleted file mode 100644 index 55c9b4f..0000000 --- a/docs/sphinx_docs/_build/html/stack.html +++ /dev/null @@ -1,298 +0,0 @@ - - - - - - - - - Stack or Quote or Sequence or List… — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Stack or Quote or Sequence or List…

-
-

joy.utils.stack

-

When talking about Joy we use the terms “stack”, “quote”, “sequence”, -“list”, and others to mean the same thing: a simple linear datatype that -permits certain operations such as iterating and pushing and popping -values from (at least) one end.

-
-

In describing Joy I have used the term quotation to describe all of the -above, because I needed a word to describe the arguments to combinators -which fulfill the same role in Joy as lambda abstractions (with -variables) fulfill in the more familiar functional languages. I use the -term list for those quotations whose members are what I call literals: -numbers, characters, truth values, sets, strings and other quotations. -All these I call literals because their occurrence in code results in -them being pushed onto the stack. But I also call [London Paris] a list. -So, [dup *] is a quotation but not a list.

-
-

“A Conversation with Manfred von Thun” w/ Stevan Apter

-

There is no “Stack” Python class, instead we use the cons list, a -venerable two-tuple recursive sequence datastructure, where the -empty tuple () is the empty stack and (head, rest) gives the -recursive form of a stack with one or more items on it:

-
stack := () | (item, stack)
-
-
-

Putting some numbers onto a stack:

-
()
-(1, ())
-(2, (1, ()))
-(3, (2, (1, ())))
-...
-
-
-

Python has very nice “tuple packing and unpacking” in its syntax which -means we can directly “unpack” the expected arguments to a Joy function.

-

For example:

-
def dup((head, tail)):
-    return head, (head, tail)
-
-
-

We replace the argument “stack” by the expected structure of the stack, -in this case “(head, tail)”, and Python takes care of unpacking the -incoming tuple and assigning values to the names. (Note that Python -syntax doesn’t require parentheses around tuples used in expressions -where they would be redundant.)

-

Unfortunately, the Sphinx documentation generator, which is used to generate this -web page, doesn’t handle tuples in the function parameters. And in Python 3, this -syntax was removed entirely. Instead you would have to write:

-
def dup(stack):
-    head, tail = stack
-    return head, (head, tail)
-
-
-

We have two very simple functions, one to build up a stack from a Python -list and another to iterate through a stack and yield its items -one-by-one in order. There are also two functions to generate string representations -of stacks. They only differ in that one prints the terms in stack from left-to-right while the other prints from right-to-left. In both functions internal stacks are -printed left-to-right. These functions are written to support Tracing Joy Execution.

-
-
-joy.utils.stack.concat(quote, expression)[source]
-

Concatinate quote onto expression.

-

In joy [1 2] [3 4] would become [1 2 3 4].

-
-
Parameters
-
    -
  • quote (stack) – A stack.

  • -
  • expression (stack) – A stack.

  • -
-
-
Return type
-

stack

-
-
-
- -
-
-joy.utils.stack.dnd(stack, from_index, to_index)[source]
-

Given a stack and two indices return a rearranged stack. -First remove the item at from_index and then insert it at to_index, -the second index is relative to the stack after removal of the item -at from_index.

-

This function reuses all of the items and as much of the stack as it -can. It’s meant to be used by remote clients to support drag-n-drop -rearranging of the stack from e.g. the StackListbox.

-
- -
-
-joy.utils.stack.expression_to_string(expression)[source]
-

Return a “pretty print” string for a expression.

-

The items are written left-to-right:

-
(top, (second, ...)) -> 'top second ...'
-
-
-
-
Parameters
-

expression (stack) – A stack.

-
-
Return type
-

str

-
-
-
- -
-
-joy.utils.stack.iter_stack(stack)[source]
-

Iterate through the items on the stack.

-
-
Parameters
-

stack (stack) – A stack.

-
-
Return type
-

iterator

-
-
-
- -
-
-joy.utils.stack.list_to_stack(el, stack=())[source]
-

Convert a Python list (or other sequence) to a Joy stack:

-
[1, 2, 3] -> (1, (2, (3, ())))
-
-
-
-
Parameters
-
    -
  • el (list) – A Python list or other sequence (iterators and generators -won’t work because reverse() is called on el.)

  • -
  • stack (stack) – A stack, optional, defaults to the empty stack. This -allows for concatinating Python lists (or other sequence objects) -onto an existing Joy stack.

  • -
-
-
Return type
-

stack

-
-
-
- -
-
-joy.utils.stack.pick(stack, n)[source]
-

Return the nth item on the stack.

-
-
Parameters
-
    -
  • stack (stack) – A stack.

  • -
  • n (int) – An index into the stack.

  • -
-
-
Raises
-
    -
  • ValueError – if n is less than zero.

  • -
  • IndexError – if n is equal to or greater than the length of stack.

  • -
-
-
Return type
-

whatever

-
-
-
- -
-
-joy.utils.stack.stack_to_string(stack)[source]
-

Return a “pretty print” string for a stack.

-

The items are written right-to-left:

-
(top, (second, ...)) -> '... second top'
-
-
-
-
Parameters
-

stack (stack) – A stack.

-
-
Return type
-

str

-
-
-
- -
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_build/html/types.html b/docs/sphinx_docs/_build/html/types.html deleted file mode 100644 index e0f9ec1..0000000 --- a/docs/sphinx_docs/_build/html/types.html +++ /dev/null @@ -1,253 +0,0 @@ - - - - - - - - - Type Inference of Joy Expressions — Thun 0.4.1 documentation - - - - - - - - - - - - - - - - - - - -
-
-
- - -
- -
-

Type Inference of Joy Expressions

-

UPDATE: May 2020 - I removed the type inference code in joy.utils.types -but you can find it in the v0.4.0 tag here: -https://osdn.net/projects/joypy/scm/hg/Joypy/tags

-

Two kinds of type inference are provided, a simple inferencer that can -handle functions that have a single stack effect (aka “type signature”) -and that can generate Python code for a limited subset of those -functions, and a more complex inferencer/interpreter hybrid that can -infer the stack effects of most Joy expressions, including multiple stack -effects, unbounded sequences of values, and combinators (if enough -information is available.)

-
-

joy.utils.types

-

Curently (asterix after name indicates a function that can be -auto-compiled to Python):

-
_Tree_add_Ee = ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) *
-_Tree_delete_R0 = ([a2 ...1] a1 -- [a2 ...1] a2 a1 a1) *
-_Tree_delete_clear_stuff = (a3 a2 [a1 ...1] -- [...1]) *
-_Tree_get_E = ([a3 a4 ...1] a2 a1 -- a4) *
-add = (n1 n2 -- n3)
-and = (b1 b2 -- b3)
-bool = (a1 -- b1)
-ccons = (a2 a1 [...1] -- [a2 a1 ...1]) *
-cons = (a1 [...0] -- [a1 ...0]) *
-div = (n1 n2 -- n3)
-divmod = (n2 n1 -- n4 n3)
-dup = (a1 -- a1 a1) *
-dupd = (a2 a1 -- a2 a2 a1) *
-dupdd = (a3 a2 a1 -- a3 a3 a2 a1) *
-eq = (n1 n2 -- b1)
-first = ([a1 ...1] -- a1) *
-first_two = ([a1 a2 ...1] -- a1 a2) *
-floordiv = (n1 n2 -- n3)
-fourth = ([a1 a2 a3 a4 ...1] -- a4) *
-ge = (n1 n2 -- b1)
-gt = (n1 n2 -- b1)
-le = (n1 n2 -- b1)
-lshift = (n1 n2 -- n3)
-lt = (n1 n2 -- b1)
-modulus = (n1 n2 -- n3)
-mul = (n1 n2 -- n3)
-ne = (n1 n2 -- b1)
-neg = (n1 -- n2)
-not = (a1 -- b1)
-over = (a2 a1 -- a2 a1 a2) *
-pm = (n2 n1 -- n4 n3)
-pop = (a1 --) *
-popd = (a2 a1 -- a1) *
-popdd = (a3 a2 a1 -- a2 a1) *
-popop = (a2 a1 --) *
-popopd = (a3 a2 a1 -- a1) *
-popopdd = (a4 a3 a2 a1 -- a2 a1) *
-pow = (n1 n2 -- n3)
-pred = (n1 -- n2)
-rest = ([a1 ...0] -- [...0]) *
-rolldown = (a1 a2 a3 -- a2 a3 a1) *
-rollup = (a1 a2 a3 -- a3 a1 a2) *
-rrest = ([a1 a2 ...1] -- [...1]) *
-rshift = (n1 n2 -- n3)
-second = ([a1 a2 ...1] -- a2) *
-sqrt = (n1 -- n2)
-stack = (... -- ... [...]) *
-stuncons = (... a1 -- ... a1 a1 [...]) *
-stununcons = (... a2 a1 -- ... a2 a1 a1 a2 [...]) *
-sub = (n1 n2 -- n3)
-succ = (n1 -- n2)
-swaack = ([...1] -- [...0]) *
-swap = (a1 a2 -- a2 a1) *
-swons = ([...1] a1 -- [a1 ...1]) *
-third = ([a1 a2 a3 ...1] -- a3) *
-truediv = (n1 n2 -- n3)
-tuck = (a2 a1 -- a1 a2 a1) *
-uncons = ([a1 ...0] -- a1 [...0]) *
-unit = (a1 -- [a1 ]) *
-unswons = ([a1 ...1] -- [...1] a1) *
-
-
-

Example output of the infer() function. The first number on each -line is the depth of the Python stack. It goes down when the function -backtracks. The next thing on each line is the currently-computed stack -effect so far. It starts with the empty “identity function” and proceeds -through the expression, which is the rest of each line. The function -acts like an interpreter but instead of executing the terms of the -expression it composes them, but for combinators it does execute them, -using the output side of the stack effect as the stack. This seems to -work fine. With proper definitions for the behavior of the combinators -that can have more than one effect (like branch or loop) the -infer() function seems to be able to handle anything I throw at it so -far.

-
  7 (--) ∘ pop swap rolldown rest rest cons cons
- 10 (a1 --) ∘ swap rolldown rest rest cons cons
- 13 (a3 a2 a1 -- a2 a3) ∘ rolldown rest rest cons cons
- 16 (a4 a3 a2 a1 -- a2 a3 a4) ∘ rest rest cons cons
- 19 ([a4 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ rest cons cons
- 22 ([a4 a5 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ cons cons
- 25 ([a4 a5 ...1] a3 a2 a1 -- a2 [a3 ...1]) ∘ cons
- 28 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘
-----------------------------------------
-([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1])
-
-
-

Here’s another example (implementing ifte) using some combinators:

-
  7 (--) ∘ [pred] [mul] [div] [nullary bool] dipd branch
-  8 (-- [pred ...2]) ∘ [mul] [div] [nullary bool] dipd branch
-  9 (-- [pred ...2] [mul ...3]) ∘ [div] [nullary bool] dipd branch
- 10 (-- [pred ...2] [mul ...3] [div ...4]) ∘ [nullary bool] dipd branch
- 11 (-- [pred ...2] [mul ...3] [div ...4] [nullary bool ...5]) ∘ dipd branch
- 15 (-- [pred ...5]) ∘ nullary bool [mul] [div] branch
- 19 (-- [pred ...2]) ∘ [stack] dinfrirst bool [mul] [div] branch
- 20 (-- [pred ...2] [stack ]) ∘ dinfrirst bool [mul] [div] branch
- 22 (-- [pred ...2] [stack ]) ∘ dip infra first bool [mul] [div] branch
- 26 (--) ∘ stack [pred] infra first bool [mul] [div] branch
- 29 (... -- ... [...]) ∘ [pred] infra first bool [mul] [div] branch
- 30 (... -- ... [...] [pred ...1]) ∘ infra first bool [mul] [div] branch
- 34 (--) ∘ pred s1 swaack first bool [mul] [div] branch
- 37 (n1 -- n2) ∘ [n1] swaack first bool [mul] [div] branch
- 38 (... n1 -- ... n2 [n1 ...]) ∘ swaack first bool [mul] [div] branch
- 41 (... n1 -- ... n1 [n2 ...]) ∘ first bool [mul] [div] branch
- 44 (n1 -- n1 n2) ∘ bool [mul] [div] branch
- 47 (n1 -- n1 b1) ∘ [mul] [div] branch
- 48 (n1 -- n1 b1 [mul ...1]) ∘ [div] branch
- 49 (n1 -- n1 b1 [mul ...1] [div ...2]) ∘ branch
- 53 (n1 -- n1) ∘ div
- 56 (f2 f1 -- f3) ∘
- 56 (i1 f1 -- f2) ∘
- 56 (f1 i1 -- f2) ∘
- 56 (i2 i1 -- f1) ∘
- 53 (n1 -- n1) ∘ mul
- 56 (f2 f1 -- f3) ∘
- 56 (i1 f1 -- f2) ∘
- 56 (f1 i1 -- f2) ∘
- 56 (i2 i1 -- i3) ∘
-----------------------------------------
-(f2 f1 -- f3)
-(i1 f1 -- f2)
-(f1 i1 -- f2)
-(i2 i1 -- f1)
-(i2 i1 -- i3)
-
-
-
-
- - -
- -
-
- -
-
- - - - \ No newline at end of file diff --git a/docs/sphinx_docs/_static/basic.css b/docs/sphinx_docs/_static/basic.css deleted file mode 100644 index ac9a52a..0000000 --- a/docs/sphinx_docs/_static/basic.css +++ /dev/null @@ -1,909 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar li { - padding-bottom: 0.5em; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li p.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 450px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, figure.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, figure.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, figure.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, figure.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar, -aside.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -aside.sidebar > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -aside.sidebar::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure, figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption, figcaption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number, -figcaption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text, -figcaption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - -/* -- object description styles --------------------------------------------- */ - -.sig { - font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; -} - -.sig-name, code.descname { - background-color: transparent; - font-weight: bold; -} - -.sig-name { - font-size: 1.1em; -} - -code.descname { - font-size: 1.2em; -} - -.sig-prename, code.descclassname { - background-color: transparent; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.sig-param.n { - font-style: italic; -} - -/* C++ specific styling */ - -.sig-inline.c-texpr, -.sig-inline.cpp-texpr { - font-family: unset; -} - -.sig.c .k, .sig.c .kt, -.sig.cpp .k, .sig.cpp .kt { - color: #0033B3; -} - -.sig.c .m, -.sig.cpp .m { - color: #1750EB; -} - -.sig.c .s, .sig.c .sc, -.sig.cpp .s, .sig.cpp .sc { - color: #067D17; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -dl.footnote > dt, -dl.citation > dt { - float: left; - margin-right: 0.5em; -} - -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; -} - -dl.footnote > dd:after, -dl.citation > dd:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dt:after { - content: ":"; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0 0.5em; - content: ":"; - display: inline-block; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; - -webkit-user-select: text; /* Safari fallback only */ - -webkit-user-select: none; /* Chrome/Safari */ - -moz-user-select: none; /* Firefox */ - -ms-user-select: none; /* IE10+ */ -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/sphinx_docs/_templates/layout.html b/docs/sphinx_docs/_templates/layout.html deleted file mode 100644 index 11d0afa..0000000 --- a/docs/sphinx_docs/_templates/layout.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "!layout.html" %} -{% block footer %} - -{% endblock %} diff --git a/docs/sphinx_docs/conf.py b/docs/sphinx_docs/conf.py deleted file mode 100644 index a33c75b..0000000 --- a/docs/sphinx_docs/conf.py +++ /dev/null @@ -1,167 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/master/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('../../implementations/Python')) - - -# -- Project information ----------------------------------------------------- - -project = u'Thun' -copyright = u'2018, Simon Forman' -author = u'Simon Forman' - -# The short X.Y version -version = u'0.4' -# The full version, including alpha/beta/rc tags -release = u'0.4.1' - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.todo', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path . -exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = 'alabaster' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'Thundoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'Thun.tex', u'Thun Documentation', - u'Simon Forman', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'thun', u'Thun Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'Thun', u'Thun Documentation', - author, 'Thun', 'One line description of project.', - 'Miscellaneous'), -] - - -# -- Extension configuration ------------------------------------------------- - -# -- Options for todo extension ---------------------------------------------- - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = True diff --git a/docs/sphinx_docs/index.rst b/docs/sphinx_docs/index.rst deleted file mode 100644 index 7cbd506..0000000 --- a/docs/sphinx_docs/index.rst +++ /dev/null @@ -1,140 +0,0 @@ -.. Thun documentation master file, created by - sphinx-quickstart on Sun Apr 22 15:19:55 2018. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Thun |release| Documentation -============================ - -Thun is dialect of Joy written in Python. - -`Joy`_ is a programming language created by Manfred von Thun that is easy to -use and understand and has many other nice properties. This Python -package implements an interpreter for a dialect of Joy that attempts to -stay very close to the spirit of Joy but does not precisely match the -behaviour of the original version(s) written in C. The main difference -between Thun and the originals, other than being written in Python, is -that it works by the "Continuation-Passing Style". - -Joy is: - -* `Purely Functional `__ -* `Stack-based `__ -* `Concatinative`_ ( See also `concatenative.org `__) -* :doc:`Categorical ` - -I hope that this package is useful in the sense that it provides an -additional joy interpreter (the binary in the archive from La Trobe seems -to run just fine on my modern Linux machine!) But I also hope that you -can read and understand the Python code and play with the implementation -itself. - -.. _Joy: https://en.wikipedia.org/wiki/Joy_(programming_language) - -.. _Concatinative: https://en.wikipedia.org/wiki/Concatenative_programming_language - - -Example Code --------------------------------------------------- - -Here is an example of Joy code:: - - [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte - -It might seem unreadable but with a little familiarity it becomes just as -legible as any other notation. Some layout helps:: - - [ [[abs] ii <=] - [ - [<>] [pop !-] || - ] && - ] - [[ !-] [[++]] [[--]] ifte dip] - [[pop !-] [--] [++] ifte ] - ifte - -This function accepts two integers on the stack and increments or -decrements one of them such that the new pair of numbers is the next -coordinate pair in a square spiral (like the kind used to construct an -`Ulam Spiral`_). For more information see :doc:`notebooks/Square_Spiral` - -.. _Ulam Spiral: https://en.wikipedia.org/wiki/Ulam_spiral - - -Quick Start --------------------------------------------------- - -Install from `PyPI`_ in the usual way:: - - $ pip install Thun - -To start the REPL:: - - $ python -m joy - -Continue with :doc:`the introduction `. - -.. _PyPI: https://pypi.org/project/Thun/ - - -Project Hosted on `OSDN`_ -------------------------- - -* `Source Repository`_ (`mirror`_) -* `Bug tracker`_ (`old tracker`_) -* `Forums`_ -* `Mailing list`_ - -.. _Bug tracker: https://todo.sr.ht/~sforman/thun-der -.. _old tracker: https://osdn.net/projects/joypy/ticket/ -.. _Forums: https://osdn.net/projects/joypy/forums/ -.. _Mailing list: https://osdn.net/projects/joypy/lists/ -.. _OSDN: https://osdn.net/projects/joypy/ -.. _Source Repository: https://osdn.net/projects/joypy/scm/git/Thun/ -.. _mirror: https://github.com/calroc/Thun - - -Information on the Joy language -------------------------------- - -See `the Wikipedia article`_ and `Kevin Albrecht's mirror of Manfred von Thun's original website for the Joy Programming Language`_ for more information on the Joy language. - -The best source (no pun intended) for learning about Joy is the -information made available at the website of La Trobe University (see the -mirror link above) which contains source code for the -original C interpreter, Joy language source code for various functions, -and a great deal of fascinating material mostly written by Von Thun on -Joy and its deeper facets as well as how to program in it and several -interesting aspects. It's quite a treasure trove. - -.. _the Wikipedia article: https://en.wikipedia.org/wiki/Joy_(programming_language) - -.. _Kevin Albrecht's mirror of Manfred von Thun's original website for the Joy Programming Language: http://www.kevinalbrecht.com/code/joy-mirror/index.html - - -Documentation on Thun Dialect ------------------------------ - -The following is specific information for this dialect of Joy. - -.. toctree:: - :maxdepth: 2 - - notebooks/Intro - joy - stack - parser - pretty - library - lib - types - notebooks/index - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/sphinx_docs/joy.rst b/docs/sphinx_docs/joy.rst deleted file mode 100644 index ad7618a..0000000 --- a/docs/sphinx_docs/joy.rst +++ /dev/null @@ -1,13 +0,0 @@ - -Joy Interpreter -=============== - - -``joy.joy`` ---------------- - - -.. automodule:: joy.joy - :members: - - diff --git a/docs/sphinx_docs/lib.rst b/docs/sphinx_docs/lib.rst deleted file mode 100644 index e341820..0000000 --- a/docs/sphinx_docs/lib.rst +++ /dev/null @@ -1,1761 +0,0 @@ - -Functions Grouped by, er, Function with Examples ------------------------------------------------- - -.. code:: python - - from notebook_preamble import J, V - -Stack Chatter -============= - -This is what I like to call the functions that just rearrange things on -the stack. (One thing I want to mention is that during a hypothetical -compilation phase these "stack chatter" words effectively disappear -because we can map the logical stack locations to registers that remain -static for the duration of the computation. This remains to be done but -it's "off the shelf" technology.) - -``clear`` -~~~~~~~~~ - -.. code:: python - - J('1 2 3 clear') - - -.. parsed-literal:: - - (nothing) - - -``dup`` ``dupd`` -~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 dup') - - -.. parsed-literal:: - - 1 2 3 3 - - -.. code:: python - - J('1 2 3 dupd') - - -.. parsed-literal:: - - 1 2 2 3 - - -``enstacken`` ``disenstacken`` ``stack`` ``unstack`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -(I may have these paired up wrong. I.e. ``disenstacken`` should be -``unstack`` and vice versa.) - -.. code:: python - - J('1 2 3 enstacken') # Replace the stack with a quote of itself. - - -.. parsed-literal:: - - [3 2 1] - - -.. code:: python - - J('4 5 6 [3 2 1] disenstacken') # Unpack a list onto the stack. - - -.. parsed-literal:: - - 4 5 6 3 2 1 - - -.. code:: python - - J('1 2 3 stack') # Get the stack on the stack. - - -.. parsed-literal:: - - 1 2 3 [3 2 1] - - -.. code:: python - - 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. - - -.. parsed-literal:: - - 6 5 4 - - -``pop`` ``popd`` ``popop`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 pop') - - -.. parsed-literal:: - - 1 2 - - -.. code:: python - - J('1 2 3 popd') - - -.. parsed-literal:: - - 1 3 - - -.. code:: python - - J('1 2 3 popop') - - -.. parsed-literal:: - - 1 - - -``roll<`` ``rolldown`` ``roll>`` ``rollup`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The "down" and "up" refer to the movement of two of the top three items -(displacing the third.) - -.. code:: python - - J('1 2 3 roll<') - - -.. parsed-literal:: - - 2 3 1 - - -.. code:: python - - J('1 2 3 roll>') - - -.. parsed-literal:: - - 3 1 2 - - -``swap`` -~~~~~~~~ - -.. code:: python - - J('1 2 3 swap') - - -.. parsed-literal:: - - 1 3 2 - - -``tuck`` ``over`` -~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 tuck') - - -.. parsed-literal:: - - 1 3 2 3 - - -.. code:: python - - J('1 2 3 over') - - -.. parsed-literal:: - - 1 2 3 2 - - -``unit`` ``quoted`` ``unquoted`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 unit') - - -.. parsed-literal:: - - 1 2 [3] - - -.. code:: python - - J('1 2 3 quoted') - - -.. parsed-literal:: - - 1 [2] 3 - - -.. code:: python - - J('1 [2] 3 unquoted') - - -.. parsed-literal:: - - 1 2 3 - - -.. code:: python - - V('1 [dup] 3 unquoted') # Unquoting evaluates. Be aware. - - -.. parsed-literal:: - - . 1 [dup] 3 unquoted - 1 . [dup] 3 unquoted - 1 [dup] . 3 unquoted - 1 [dup] 3 . unquoted - 1 [dup] 3 . [i] dip - 1 [dup] 3 [i] . dip - 1 [dup] . i 3 - 1 . dup 3 - 1 1 . 3 - 1 1 3 . - - -List words -========== - -``concat`` ``swoncat`` ``shunt`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3] [4 5 6] concat') - - -.. parsed-literal:: - - [1 2 3 4 5 6] - - -.. code:: python - - J('[1 2 3] [4 5 6] swoncat') - - -.. parsed-literal:: - - [4 5 6 1 2 3] - - -.. code:: python - - J('[1 2 3] [4 5 6] shunt') - - -.. parsed-literal:: - - [6 5 4 1 2 3] - - -``cons`` ``swons`` ``uncons`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 [2 3] cons') - - -.. parsed-literal:: - - [1 2 3] - - -.. code:: python - - J('[2 3] 1 swons') - - -.. parsed-literal:: - - [1 2 3] - - -.. code:: python - - J('[1 2 3] uncons') - - -.. parsed-literal:: - - 1 [2 3] - - -``first`` ``second`` ``third`` ``rest`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 4] first') - - -.. parsed-literal:: - - 1 - - -.. code:: python - - J('[1 2 3 4] second') - - -.. parsed-literal:: - - 2 - - -.. code:: python - - J('[1 2 3 4] third') - - -.. parsed-literal:: - - 3 - - -.. code:: python - - J('[1 2 3 4] rest') - - -.. parsed-literal:: - - [2 3 4] - - -``flatten`` -~~~~~~~~~~~ - -.. code:: python - - J('[[1] [2 [3] 4] [5 6]] flatten') - - -.. parsed-literal:: - - [1 2 [3] 4 5 6] - - -``getitem`` ``at`` ``of`` ``drop`` ``take`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``at`` and ``getitem`` are the same function. ``of == swap at`` - -.. code:: python - - J('[10 11 12 13 14] 2 getitem') - - -.. parsed-literal:: - - 12 - - -.. code:: python - - J('[1 2 3 4] 0 at') - - -.. parsed-literal:: - - 1 - - -.. code:: python - - J('2 [1 2 3 4] of') - - -.. parsed-literal:: - - 3 - - -.. code:: python - - J('[1 2 3 4] 2 drop') - - -.. parsed-literal:: - - [3 4] - - -.. code:: python - - J('[1 2 3 4] 2 take') # reverses the order - - -.. parsed-literal:: - - [2 1] - - -``reverse`` could be defines as ``reverse == dup size take`` - -``remove`` -~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 1 4] 1 remove') - - -.. parsed-literal:: - - [2 3 1 4] - - -``reverse`` -~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 4] reverse') - - -.. parsed-literal:: - - [4 3 2 1] - - -``size`` -~~~~~~~~ - -.. code:: python - - J('[1 1 1 1] size') - - -.. parsed-literal:: - - 4 - - -``swaack`` -~~~~~~~~~~ - -"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. Neither of the lists/stacks change their order. - -.. code:: python - - J('1 2 3 [4 5 6] swaack') - - -.. parsed-literal:: - - 6 5 4 [3 2 1] - - -``choice`` ``select`` -~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 1 choice') - - -.. parsed-literal:: - - 9 - - -.. code:: python - - J('23 9 0 choice') - - -.. parsed-literal:: - - 23 - - -.. code:: python - - J('[23 9 7] 1 select') # select is basically getitem, should retire it? - - -.. parsed-literal:: - - 9 - - -.. code:: python - - J('[23 9 7] 0 select') - - -.. parsed-literal:: - - 23 - - -``zip`` -~~~~~~~ - -.. code:: python - - J('[1 2 3] [6 5 4] zip') - - -.. parsed-literal:: - - [[6 1] [5 2] [4 3]] - - -.. code:: python - - J('[1 2 3] [6 5 4] zip [sum] map') - - -.. parsed-literal:: - - [7 7 7] - - -Math words -========== - -``+`` ``add`` -~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 +') - - -.. parsed-literal:: - - 32 - - -``-`` ``sub`` -~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 -') - - -.. parsed-literal:: - - 14 - - -``*`` ``mul`` -~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 *') - - -.. parsed-literal:: - - 207 - - -``/`` ``div`` ``floordiv`` ``truediv`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 /') - - -.. parsed-literal:: - - 2.5555555555555554 - - -.. code:: python - - J('23 -9 truediv') - - -.. parsed-literal:: - - -2.5555555555555554 - - -.. code:: python - - J('23 9 div') - - -.. parsed-literal:: - - 2 - - -.. code:: python - - J('23 9 floordiv') - - -.. parsed-literal:: - - 2 - - -.. code:: python - - J('23 -9 div') - - -.. parsed-literal:: - - -3 - - -.. code:: python - - J('23 -9 floordiv') - - -.. parsed-literal:: - - -3 - - -``%`` ``mod`` ``modulus`` ``rem`` ``remainder`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 %') - - -.. parsed-literal:: - - 5 - - -``neg`` -~~~~~~~ - -.. code:: python - - J('23 neg -5 neg') - - -.. parsed-literal:: - - -23 5 - - -``pow`` -~~~~~~~ - -.. code:: python - - J('2 10 pow') - - -.. parsed-literal:: - - 1024 - - -``sqr`` ``sqrt`` -~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 sqr') - - -.. parsed-literal:: - - 529 - - -.. code:: python - - J('23 sqrt') - - -.. parsed-literal:: - - 4.795831523312719 - - -``++`` ``succ`` ``--`` ``pred`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 ++') - - -.. parsed-literal:: - - 2 - - -.. code:: python - - J('1 --') - - -.. parsed-literal:: - - 0 - - -``<<`` ``lshift`` ``>>`` ``rshift`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('8 1 <<') - - -.. parsed-literal:: - - 16 - - -.. code:: python - - J('8 1 >>') - - -.. parsed-literal:: - - 4 - - -``average`` -~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 5] average') - - -.. parsed-literal:: - - 2.75 - - -``range`` ``range_to_zero`` ``down_to_zero`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('5 range') - - -.. parsed-literal:: - - [4 3 2 1 0] - - -.. code:: python - - J('5 range_to_zero') - - -.. parsed-literal:: - - [0 1 2 3 4 5] - - -.. code:: python - - J('5 down_to_zero') - - -.. parsed-literal:: - - 5 4 3 2 1 0 - - -``product`` -~~~~~~~~~~~ - -.. code:: python - - J('[1 2 3 5] product') - - -.. parsed-literal:: - - 30 - - -``sum`` -~~~~~~~ - -.. code:: python - - J('[1 2 3 5] sum') - - -.. parsed-literal:: - - 11 - - -``min`` -~~~~~~~ - -.. code:: python - - J('[1 2 3 5] min') - - -.. parsed-literal:: - - 1 - - -``gcd`` -~~~~~~~ - -.. code:: python - - J('45 30 gcd') - - -.. parsed-literal:: - - 15 - - -``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. - -.. code:: python - - J('[45 30] least_fraction') - - -.. parsed-literal:: - - [3 2] - - -.. code:: python - - J('[23 12] least_fraction') - - -.. parsed-literal:: - - [23 12] - - -Logic and Comparison -==================== - -``?`` ``truthy`` -~~~~~~~~~~~~~~~~ - -Get the Boolean value of the item on the top of the stack. - -.. code:: python - - J('23 truthy') - - -.. parsed-literal:: - - True - - -.. code:: python - - J('[] truthy') # Python semantics. - - -.. parsed-literal:: - - False - - -.. code:: python - - J('0 truthy') - - -.. parsed-literal:: - - False - - -:: - - ? == dup truthy - -.. code:: python - - V('23 ?') - - -.. parsed-literal:: - - . 23 ? - 23 . ? - 23 . dup truthy - 23 23 . truthy - 23 True . - - -.. code:: python - - J('[] ?') - - -.. parsed-literal:: - - [] False - - -.. code:: python - - J('0 ?') - - -.. parsed-literal:: - - 0 False - - -``&`` ``and`` -~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 &') - - -.. parsed-literal:: - - 1 - - -``!=`` ``<>`` ``ne`` -~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('23 9 !=') - - -.. parsed-literal:: - - True - - -| The usual suspects: - ``<`` ``lt`` - ``<=`` ``le`` -| - ``=`` ``eq`` - ``>`` ``gt`` - ``>=`` ``ge`` - ``not`` - ``or`` - -``^`` ``xor`` -~~~~~~~~~~~~~ - -.. code:: python - - J('1 1 ^') - - -.. parsed-literal:: - - 0 - - -.. code:: python - - J('1 0 ^') - - -.. parsed-literal:: - - 1 - - -Miscellaneous -============= - -``help`` -~~~~~~~~ - -.. code:: python - - J('[help] help') - - -.. parsed-literal:: - - Accepts a quoted symbol on the top of the stack and prints its docs. - - - -``parse`` -~~~~~~~~~ - -.. code:: python - - J('[parse] help') - - -.. parsed-literal:: - - Parse the string on the stack to a Joy expression. - - - -.. code:: python - - J('1 "2 [3] dup" parse') - - -.. parsed-literal:: - - 1 [2 [3] dup] - - -``run`` -~~~~~~~ - -Evaluate a quoted Joy sequence. - -.. code:: python - - J('[1 2 dup + +] run') - - -.. parsed-literal:: - - [5] - - -Combinators -=========== - -``app1`` ``app2`` ``app3`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[app1] help') - - -.. parsed-literal:: - - Given a quoted program on TOS and anything as the second stack item run - the program and replace the two args with the first result of the - program. - - ... x [Q] . app1 - ----------------------------------- - ... [x ...] [Q] . infra first - - - -.. code:: python - - J('10 4 [sqr *] app1') - - -.. parsed-literal:: - - 10 160 - - -.. code:: python - - J('10 3 4 [sqr *] app2') - - -.. parsed-literal:: - - 10 90 160 - - -.. code:: python - - J('[app2] help') - - -.. parsed-literal:: - - Like app1 with two items. - - ... y x [Q] . app2 - ----------------------------------- - ... [y ...] [Q] . infra first - [x ...] [Q] infra first - - - -.. code:: python - - J('10 2 3 4 [sqr *] app3') - - -.. parsed-literal:: - - 10 40 90 160 - - -``anamorphism`` -~~~~~~~~~~~~~~~ - -Given an initial value, a predicate function ``[P]``, and a generator -function ``[G]``, the ``anamorphism`` combinator creates a sequence. - -:: - - n [P] [G] anamorphism - --------------------------- - [...] - -Example, ``range``: - -:: - - range == [0 <=] [1 - dup] anamorphism - -.. code:: python - - J('3 [0 <=] [1 - dup] anamorphism') - - -.. parsed-literal:: - - [2 1 0] - - -``branch`` -~~~~~~~~~~ - -.. code:: python - - J('3 4 1 [+] [*] branch') - - -.. parsed-literal:: - - 12 - - -.. code:: python - - J('3 4 0 [+] [*] branch') - - -.. parsed-literal:: - - 7 - - -``cleave`` -~~~~~~~~~~ - -:: - - ... x [P] [Q] cleave - -From the original Joy docs: "The cleave combinator expects two -quotations, and below that an item ``x`` It first executes ``[P]``, with -``x`` on top, and saves the top result element. Then it executes -``[Q]``, again with ``x``, and saves the top result. Finally it restores -the stack to what it was below ``x`` and pushes the two results P(X) and -Q(X)." - -Note that ``P`` and ``Q`` can use items from the stack freely, since the -stack (below ``x``) is restored. ``cleave`` is a kind of *parallel* -primitive, and it would make sense to create a version that uses, e.g. -Python threads or something, to actually run ``P`` and ``Q`` -concurrently. The current implementation of ``cleave`` is a definition -in terms of ``app2``: - -:: - - cleave == [i] app2 [popd] dip - -.. code:: python - - J('10 2 [+] [-] cleave') - - -.. parsed-literal:: - - 10 12 8 - - -``dip`` ``dipd`` ``dipdd`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('1 2 3 4 5 [+] dip') - - -.. parsed-literal:: - - 1 2 7 5 - - -.. code:: python - - J('1 2 3 4 5 [+] dipd') - - -.. parsed-literal:: - - 1 5 4 5 - - -.. code:: python - - J('1 2 3 4 5 [+] dipdd') - - -.. parsed-literal:: - - 3 3 4 5 - - -``dupdip`` -~~~~~~~~~~ - -Expects a quoted program ``[Q]`` on the stack and some item under it, -``dup`` the item and ``dip`` the quoted program under it. - -:: - - n [Q] dupdip == n Q n - -.. code:: python - - V('23 [++] dupdip *') # N(N + 1) - - -.. parsed-literal:: - - . 23 [++] dupdip * - 23 . [++] dupdip * - 23 [++] . dupdip * - 23 . ++ 23 * - 24 . 23 * - 24 23 . * - 552 . - - -``genrec`` ``primrec`` -~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[genrec] help') - - -.. parsed-literal:: - - General Recursion Combinator. - - [if] [then] [rec1] [rec2] genrec - --------------------------------------------------------------------- - [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte - - From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun: - "The genrec combinator takes four program parameters in addition to - whatever data parameters it needs. Fourth from the top is an if-part, - followed by a then-part. If the if-part yields true, then the then-part - is executed and the combinator terminates. The other two parameters are - the rec1-part and the rec2-part. If the if-part yields false, the - rec1-part is executed. Following that the four program parameters and - the combinator are again pushed onto the stack bundled up in a quoted - form. Then the rec2-part is executed, where it will find the bundled - form. Typically it will then execute the bundled form, either with i or - with app2, or some other combinator." - - The way to design one of these is to fix your base case [then] and the - test [if], and then treat rec1 and rec2 as an else-part "sandwiching" - a quotation of the whole function. - - For example, given a (general recursive) function 'F': - - F == [I] [T] [R1] [R2] genrec - - If the [I] if-part fails you must derive R1 and R2 from: - - ... R1 [F] R2 - - Just set the stack arguments in front, and figure out what R1 and R2 - have to do to apply the quoted [F] in the proper way. In effect, the - genrec combinator turns into an ifte combinator with a quoted copy of - the original definition in the else-part: - - F == [I] [T] [R1] [R2] genrec - == [I] [T] [R1 [F] R2] ifte - - (Primitive recursive functions are those where R2 == i. - - P == [I] [T] [R] primrec - == [I] [T] [R [P] i] ifte - == [I] [T] [R P] ifte - ) - - - -.. code:: python - - J('3 [1 <=] [] [dup --] [i *] genrec') - - -.. parsed-literal:: - - 6 - - -``i`` -~~~~~ - -.. code:: python - - V('1 2 3 [+ +] i') - - -.. parsed-literal:: - - . 1 2 3 [+ +] i - 1 . 2 3 [+ +] i - 1 2 . 3 [+ +] i - 1 2 3 . [+ +] i - 1 2 3 [+ +] . i - 1 2 3 . + + - 1 5 . + - 6 . - - -``ifte`` -~~~~~~~~ - -:: - - [predicate] [then] [else] ifte - -.. code:: python - - J('1 2 [1] [+] [*] ifte') - - -.. parsed-literal:: - - 3 - - -.. code:: python - - J('1 2 [0] [+] [*] ifte') - - -.. parsed-literal:: - - 2 - - -``infra`` -~~~~~~~~~ - -.. code:: python - - V('1 2 3 [4 5 6] [* +] infra') - - -.. parsed-literal:: - - . 1 2 3 [4 5 6] [* +] infra - 1 . 2 3 [4 5 6] [* +] infra - 1 2 . 3 [4 5 6] [* +] infra - 1 2 3 . [4 5 6] [* +] infra - 1 2 3 [4 5 6] . [* +] infra - 1 2 3 [4 5 6] [* +] . infra - 6 5 4 . * + [3 2 1] swaack - 6 20 . + [3 2 1] swaack - 26 . [3 2 1] swaack - 26 [3 2 1] . swaack - 1 2 3 [26] . - - -``loop`` -~~~~~~~~ - -.. code:: python - - J('[loop] help') - - -.. parsed-literal:: - - Basic loop combinator. - - ... True [Q] loop - ----------------------- - ... Q [Q] loop - - ... False [Q] loop - ------------------------ - ... - - - -.. code:: python - - V('3 dup [1 - dup] loop') - - -.. parsed-literal:: - - . 3 dup [1 - dup] loop - 3 . dup [1 - dup] loop - 3 3 . [1 - dup] loop - 3 3 [1 - dup] . loop - 3 . 1 - dup [1 - dup] loop - 3 1 . - dup [1 - dup] loop - 2 . dup [1 - dup] loop - 2 2 . [1 - dup] loop - 2 2 [1 - dup] . loop - 2 . 1 - dup [1 - dup] loop - 2 1 . - dup [1 - dup] loop - 1 . dup [1 - dup] loop - 1 1 . [1 - dup] loop - 1 1 [1 - dup] . loop - 1 . 1 - dup [1 - dup] loop - 1 1 . - dup [1 - dup] loop - 0 . dup [1 - dup] loop - 0 0 . [1 - dup] loop - 0 0 [1 - dup] . loop - 0 . - - -``map`` ``pam`` -~~~~~~~~~~~~~~~ - -.. code:: python - - J('10 [1 2 3] [*] map') - - -.. parsed-literal:: - - 10 [10 20 30] - - -.. code:: python - - J('10 5 [[*][/][+][-]] pam') - - -.. parsed-literal:: - - 10 5 [50 2.0 15 5] - - -``nullary`` ``unary`` ``binary`` ``ternary`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Run a quoted program enforcing -`arity `__. - -.. code:: python - - J('1 2 3 4 5 [+] nullary') - - -.. parsed-literal:: - - 1 2 3 4 5 9 - - -.. code:: python - - J('1 2 3 4 5 [+] unary') - - -.. parsed-literal:: - - 1 2 3 4 9 - - -.. code:: python - - J('1 2 3 4 5 [+] binary') # + has arity 2 so this is technically pointless... - - -.. parsed-literal:: - - 1 2 3 9 - - -.. code:: python - - J('1 2 3 4 5 [+] ternary') - - -.. parsed-literal:: - - 1 2 9 - - -``step`` -~~~~~~~~ - -.. code:: python - - J('[step] help') - - -.. parsed-literal:: - - Run a quoted program on each item in a sequence. - - ... [] [Q] . step - ----------------------- - ... . - - - ... [a] [Q] . step - ------------------------ - ... a . Q - - - ... [a b c] [Q] . step - ---------------------------------------- - ... a . Q [b c] [Q] step - - The step combinator executes the quotation on each member of the list - on top of the stack. - - - -.. code:: python - - V('0 [1 2 3] [+] step') - - -.. parsed-literal:: - - . 0 [1 2 3] [+] step - 0 . [1 2 3] [+] step - 0 [1 2 3] . [+] step - 0 [1 2 3] [+] . step - 0 1 [+] . i [2 3] [+] step - 0 1 . + [2 3] [+] step - 1 . [2 3] [+] step - 1 [2 3] . [+] step - 1 [2 3] [+] . step - 1 2 [+] . i [3] [+] step - 1 2 . + [3] [+] step - 3 . [3] [+] step - 3 [3] . [+] step - 3 [3] [+] . step - 3 3 [+] . i - 3 3 . + - 6 . - - -``times`` -~~~~~~~~~ - -.. code:: python - - V('3 2 1 2 [+] times') - - -.. parsed-literal:: - - . 3 2 1 2 [+] times - 3 . 2 1 2 [+] times - 3 2 . 1 2 [+] times - 3 2 1 . 2 [+] times - 3 2 1 2 . [+] times - 3 2 1 2 [+] . times - 3 2 1 . + 1 [+] times - 3 3 . 1 [+] times - 3 3 1 . [+] times - 3 3 1 [+] . times - 3 3 . + - 6 . - - -``b`` -~~~~~ - -.. code:: python - - J('[b] help') - - -.. parsed-literal:: - - b == [i] dip i - - ... [P] [Q] b == ... [P] i [Q] i - ... [P] [Q] b == ... P Q - - - -.. code:: python - - V('1 2 [3] [4] b') - - -.. parsed-literal:: - - . 1 2 [3] [4] b - 1 . 2 [3] [4] b - 1 2 . [3] [4] b - 1 2 [3] . [4] b - 1 2 [3] [4] . b - 1 2 . 3 4 - 1 2 3 . 4 - 1 2 3 4 . - - -``while`` -~~~~~~~~~ - -:: - - [predicate] [body] while - -.. code:: python - - J('3 [0 >] [dup --] while') - - -.. parsed-literal:: - - 3 2 1 0 - - -``x`` -~~~~~ - -.. code:: python - - J('[x] help') - - -.. parsed-literal:: - - x == dup i - - ... [Q] x = ... [Q] dup i - ... [Q] x = ... [Q] [Q] i - ... [Q] x = ... [Q] Q - - - -.. code:: python - - V('1 [2] [i 3] x') # Kind of a pointless example. - - -.. parsed-literal:: - - . 1 [2] [i 3] x - 1 . [2] [i 3] x - 1 [2] . [i 3] x - 1 [2] [i 3] . x - 1 [2] [i 3] . i 3 - 1 [2] . i 3 3 - 1 . 2 3 3 - 1 2 . 3 3 - 1 2 3 . 3 - 1 2 3 3 . - - -``void`` -======== - -Implements `**Laws of Form** -*arithmetic* `__ -over quote-only datastructures (that is, datastructures that consist -soley of containers, without strings or numbers or anything else.) - -.. code:: python - - J('[] void') - - -.. parsed-literal:: - - False - - -.. code:: python - - J('[[]] void') - - -.. parsed-literal:: - - True - - -.. code:: python - - J('[[][[]]] void') - - -.. parsed-literal:: - - True - - -.. code:: python - - J('[[[]][[][]]] void') - - -.. parsed-literal:: - - False - diff --git a/docs/sphinx_docs/library.rst b/docs/sphinx_docs/library.rst deleted file mode 100644 index 63a621e..0000000 --- a/docs/sphinx_docs/library.rst +++ /dev/null @@ -1,19 +0,0 @@ - -Function Reference -====================================== - - -``joy.library`` ----------------------- - - -.. automodule:: joy.library - :members: - - -Auto-generated Functions ---------------------------- - -.. automodule:: joy.utils.generated_library - :members: - diff --git a/docs/sphinx_docs/notebooks/Categorical.rst b/docs/sphinx_docs/notebooks/Categorical.rst deleted file mode 100644 index 979ec20..0000000 --- a/docs/sphinx_docs/notebooks/Categorical.rst +++ /dev/null @@ -1,17 +0,0 @@ - -*********************** -Categorical Programming -*********************** - -DRAFT - -`Categorical `__ - -In Manfred von Thun's article `Joy compared with other functional languages `__ he asks, "Could the language of categories be used for writing programs? Any lambda expression can be translated into a categorical expression, so the language of categories is expressively complete. But this does not make it a suitable language for writing programs. As it stands it is a very low-level language." - -In `Compiling to categories `__ Conal Elliott give a taste of what this might mean. - - It is well-known that the simply typed lambda-calculus is modeled by any cartesian closed category (CCC). This correspondence suggests giving typed functional programs a variety of interpretations, each corresponding to a different category. A convenient way to realize this idea is as a collection of meaning-preserving transformations added to an existing compiler, such as GHC for Haskell. This paper describes such an implementation and demonstrates its use for a variety of interpretations including hardware circuits, automatic differentiation, incremental computation, and interval analysis. Each such interpretation is a category easily defined in Haskell (outside of the compiler). The general technique appears to provide a compelling alternative to deeply embedded domain-specific languages. - -What he's doing is translating lambda forms into a kind of "point-free" style that is very close to Joy code (although more verbose) and then showing how to instantiate that code over different categories to get several different kinds of program out of the same code. - diff --git a/docs/sphinx_docs/notebooks/Derivatives_of_Regular_Expressions.rst b/docs/sphinx_docs/notebooks/Derivatives_of_Regular_Expressions.rst deleted file mode 100644 index 68d6363..0000000 --- a/docs/sphinx_docs/notebooks/Derivatives_of_Regular_Expressions.rst +++ /dev/null @@ -1,946 +0,0 @@ -∂RE -=== - -Brzozowski’s Derivatives of Regular Expressions ------------------------------------------------ - -Legend: - -:: - - ∧ intersection - ∨ union - ∘ concatenation (see below) - ¬ complement - ϕ empty set (aka ∅) - λ singleton set containing just the empty string - I set of all letters in alphabet - -Derivative of a set ``R`` of strings and a string ``a``: - -:: - - ∂a(R) - - ∂a(a) → λ - ∂a(λ) → ϕ - ∂a(ϕ) → ϕ - ∂a(¬a) → ϕ - ∂a(R*) → ∂a(R)∘R* - ∂a(¬R) → ¬∂a(R) - ∂a(R∘S) → ∂a(R)∘S ∨ δ(R)∘∂a(S) - ∂a(R ∧ S) → ∂a(R) ∧ ∂a(S) - ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S) - - ∂ab(R) = ∂b(∂a(R)) - -Auxiliary predicate function ``δ`` (I call it ``nully``) returns either -``λ`` if ``λ ⊆ R`` or ``ϕ`` otherwise: - -:: - - δ(a) → ϕ - δ(λ) → λ - δ(ϕ) → ϕ - δ(R*) → λ - δ(¬R) δ(R)≟ϕ → λ - δ(¬R) δ(R)≟λ → ϕ - δ(R∘S) → δ(R) ∧ δ(S) - δ(R ∧ S) → δ(R) ∧ δ(S) - δ(R ∨ S) → δ(R) ∨ δ(S) - -Some rules we will use later for “compaction”: - -:: - - R ∧ ϕ = ϕ ∧ R = ϕ - - R ∧ I = I ∧ R = R - - R ∨ ϕ = ϕ ∨ R = R - - R ∨ I = I ∨ R = I - - R∘ϕ = ϕ∘R = ϕ - - R∘λ = λ∘R = R - -Concatination of sets: for two sets A and B the set A∘B is defined as: - -{a∘b for a in A for b in B} - -E.g.: - -{‘a’, ‘b’}∘{‘c’, ‘d’} → {‘ac’, ‘ad’, ‘bc’, ‘bd’} - -Implementation --------------- - -.. code:: ipython2 - - from functools import partial as curry - from itertools import product - -``ϕ`` and ``λ`` -~~~~~~~~~~~~~~~ - -The empty set and the set of just the empty string. - -.. code:: ipython2 - - phi = frozenset() # ϕ - y = frozenset({''}) # λ - -Two-letter Alphabet -~~~~~~~~~~~~~~~~~~~ - -I’m only going to use two symbols (at first) becaase this is enough to -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. - -.. code:: ipython2 - - syms = O, l = frozenset({'0'}), frozenset({'1'}) - -Representing Regular Expressions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To represent REs in Python I’m going to use tagged tuples. A *regular -expression* is one of: - -:: - - O - l - (KSTAR, R) - (NOT, R) - (AND, R, S) - (CONS, R, S) - (OR, R, S) - -Where ``R`` and ``S`` stand for *regular expressions*. - -.. code:: ipython2 - - AND, CONS, KSTAR, NOT, OR = 'and cons * not or'.split() # Tags are just strings. - -Because they are formed of ``frozenset``, ``tuple`` and ``str`` objects -only, these datastructures are immutable. - -String Representation of RE Datastructures -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: ipython2 - - 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 - -``I`` -~~~~~ - -Match anything. Often spelled “.” - -:: - - I = (0|1)* - -.. code:: ipython2 - - I = (KSTAR, (OR, O, l)) - -.. code:: ipython2 - - print stringy(I) - - -.. parsed-literal:: - - . - - -``(.111.) & (.01 + 11*)'`` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The example expression from Brzozowski: - -:: - - (.111.) & (.01 + 11*)' - a & (b + c)' - -Note that it contains one of everything. - -.. code:: ipython2 - - a = (CONS, I, (CONS, l, (CONS, l, (CONS, l, I)))) - b = (CONS, I, (CONS, O, l)) - c = (CONS, l, (KSTAR, l)) - it = (AND, a, (NOT, (OR, b, c))) - -.. code:: ipython2 - - print stringy(it) - - -.. parsed-literal:: - - (.111.) & ((.01 | 11*)') - - -``nully()`` -~~~~~~~~~~~ - -Let’s get that auxiliary predicate function ``δ`` out of the way. - -.. code:: ipython2 - - def nully(R): - ''' - δ - Return λ if λ ⊆ R otherwise ϕ. - ''' - - # δ(a) → ϕ - # δ(ϕ) → ϕ - if R in syms or R == phi: - return phi - - # δ(λ) → λ - if R == y: - return y - - tag = R[0] - - # δ(R*) → λ - if tag == KSTAR: - return 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 - -No “Compaction” -~~~~~~~~~~~~~~~ - -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 - - def D(symbol): - - def derv(R): - - # ∂a(a) → λ - if R == {symbol}: - return y - - # ∂a(λ) → ϕ - # ∂a(ϕ) → ϕ - # ∂a(¬a) → ϕ - if R == y or R == phi or R in syms: - return phi - - tag = R[0] - - # ∂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])) - - 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) ∧ ∂a(S) - # ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S) - return (tag, derv(r), derv(s)) - - return derv - -Compaction Rules -~~~~~~~~~~~~~~~~ - -.. code:: ipython2 - - 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. - -.. code:: ipython2 - - # 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∘ϕ = ϕ∘R = ϕ - _cons = curry(_compaction_rule, CONS, y, phi) - -Memoizing -~~~~~~~~~ - -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 - - class Memo(object): - - 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 - -With “Compaction” -~~~~~~~~~~~~~~~~~ - -This version uses the rules above to perform compaction. It keeps the -expressions from growing too large. - -.. code:: ipython2 - - def D_compaction(symbol): - - @Memo - def derv(R): - - # ∂a(a) → λ - if R == {symbol}: - return y - - # ∂a(λ) → ϕ - # ∂a(ϕ) → ϕ - # ∂a(¬a) → ϕ - if R == y or R == phi or R in syms: - return phi - - tag = R[0] - - # ∂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])) - - 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) ∧ ∂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 - -Let’s try it out… ------------------ - -(FIXME: redo.) - -.. code:: ipython2 - - 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 - - -.. parsed-literal:: - - (.111.) & ((.01 | 11*)') - - 92 / 122 - 92 / 122 - - (.01)' - (.01 | 1)' - (.01 | ^)' - (.01 | 1*)' - (.111.) & ((.01 | 1)') - (.111. | 11.) & ((.01 | ^)') - (.111. | 11. | 1.) & ((.01)') - (.111. | 11.) & ((.01 | 1*)') - (.111. | 11. | 1.) & ((.01 | 1*)') - - -Should match: - -:: - - (.111.) & ((.01 | 11*)') - - 92 / 122 - 92 / 122 - - (.01 )' - (.01 | 1 )' - (.01 | ^ )' - (.01 | 1*)' - (.111.) & ((.01 | 1 )') - (.111. | 11.) & ((.01 | ^ )') - (.111. | 11.) & ((.01 | 1*)') - (.111. | 11. | 1.) & ((.01 )') - (.111. | 11. | 1.) & ((.01 | 1*)') - -Larger Alphabets ----------------- - -We could parse larger alphabets by defining patterns for e.g. each byte -of the ASCII code. Or we can generalize this code. If you study the code -above you’ll see that we never use the “set-ness” of the symbols ``O`` -and ``l``. The only time Python set operators (``&`` and ``|``) appear -is in the ``nully()`` function, and there they operate on (recursively -computed) outputs of that function, never ``O`` and ``l``. - -What if we try: - -:: - - (OR, O, l) - - ∂1((OR, O, l)) - ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S) - ∂1(O) ∨ ∂1(l) - ∂a(¬a) → ϕ - ϕ ∨ ∂1(l) - ∂a(a) → λ - ϕ ∨ λ - ϕ ∨ R = R - λ - -And compare it to: - -:: - - {'0', '1') - - ∂1({'0', '1')) - ∂a(R ∨ S) → ∂a(R) ∨ ∂a(S) - ∂1({'0')) ∨ ∂1({'1')) - ∂a(¬a) → ϕ - ϕ ∨ ∂1({'1')) - ∂a(a) → λ - ϕ ∨ λ - ϕ ∨ R = R - λ - -This suggests that we should be able to alter the functions above to -detect sets and deal with them appropriately. Exercise for the Reader -for now. - -State Machine -------------- - -We can drive the regular expressions to flesh out the underlying state -machine transition table. - -:: - - .111. & (.01 + 11*)' - -Says, “Three or more 1’s and not ending in 01 nor composed of all 1’s.” - -.. figure:: omg.svg - :alt: State Machine Graph - - State Machine Graph - -Start at ``a`` and follow the transition arrows according to their -labels. Accepting states have a double outline. (Graphic generated with -`Dot from Graphviz `__.) You’ll see that only -paths that lead to one of the accepting states will match the regular -expression. All other paths will terminate at one of the non-accepting -states. - -There’s a happy path to ``g`` along 111: - -:: - - a→c→e→g - -After you reach ``g`` you’re stuck there eating 1’s until you see a 0, -which takes you to the ``i→j→i|i→j→h→i`` “trap”. You can’t reach any -other states from those two loops. - -If you see a 0 before you see 111 you will reach ``b``, which forms -another “trap” with ``d`` and ``f``. The only way out is another happy -path along 111 to ``h``: - -:: - - b→d→f→h - -Once you have reached ``h`` you can see as many 1’s or as many 0’ in a -row and still be either still at ``h`` (for 1’s) or move to ``i`` (for -0’s). If you find yourself at ``i`` you can see as many 0’s, or -repetitions of 10, as there are, but if you see just a 1 you move to -``j``. - -RE to FSM -~~~~~~~~~ - -So how do we get the state machine from the regular expression? - -It turns out that each RE is effectively a state, and each arrow points -to the derivative RE in respect to the arrow’s symbol. - -If we label the initial RE ``a``, we can say: - -:: - - a --0--> ∂0(a) - a --1--> ∂1(a) - -And so on, each new unique RE is a new state in the FSM table. - -Here are the derived REs at each state: - -:: - - a = (.111.) & ((.01 | 11*)') - b = (.111.) & ((.01 | 1)') - c = (.111. | 11.) & ((.01 | 1*)') - d = (.111. | 11.) & ((.01 | ^)') - e = (.111. | 11. | 1.) & ((.01 | 1*)') - f = (.111. | 11. | 1.) & ((.01)') - g = (.01 | 1*)' - h = (.01)' - i = (.01 | 1)' - j = (.01 | ^)' - -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 - - from collections import defaultdict - from pprint import pprint - from string import ascii_lowercase - -.. code:: ipython2 - - d0, d1 = D_compaction('0'), D_compaction('1') - -``explore()`` -~~~~~~~~~~~~~ - -.. code:: ipython2 - - def explore(re): - - # Don't have more than 26 states... - names = defaultdict(iter(ascii_lowercase).next) - - table, accepting = dict(), set() - - to_check = {re} - while to_check: - - re = to_check.pop() - state_name = names[re] - - if (state_name, 0) in table: - continue - - 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) - - return table, accepting - -.. code:: ipython2 - - table, accepting = explore(it) - table - - - - -.. parsed-literal:: - - {('a', 0): 'b', - ('a', 1): 'c', - ('b', 0): 'b', - ('b', 1): 'd', - ('c', 0): 'b', - ('c', 1): 'e', - ('d', 0): 'b', - ('d', 1): 'f', - ('e', 0): 'b', - ('e', 1): 'g', - ('f', 0): 'b', - ('f', 1): 'h', - ('g', 0): 'i', - ('g', 1): 'g', - ('h', 0): 'i', - ('h', 1): 'h', - ('i', 0): 'i', - ('i', 1): 'j', - ('j', 0): 'i', - ('j', 1): 'h'} - - - -.. code:: ipython2 - - accepting - - - - -.. parsed-literal:: - - {'h', 'i'} - - - -Generate Diagram -~~~~~~~~~~~~~~~~ - -Once we have the FSM table and the set of accepting states we can -generate the diagram above. - -.. code:: ipython2 - - _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 make_graph(table, accepting): - return _template % ( - ' '.join(accepting), - '\n'.join( - link(from_, to, char) - for (from_, char), (to) in sorted(table.iteritems()) - ) - ) - -.. code:: ipython2 - - print make_graph(table, accepting) - - -.. parsed-literal:: - - digraph finite_state_machine { - rankdir=LR; - size="8,5" - node [shape = doublecircle]; i h; - node [shape = circle]; - a -> b [ label = "0" ]; - a -> c [ label = "1" ]; - b -> b [ label = "0" ]; - b -> d [ label = "1" ]; - c -> b [ label = "0" ]; - c -> e [ label = "1" ]; - d -> b [ label = "0" ]; - d -> f [ label = "1" ]; - e -> b [ label = "0" ]; - e -> g [ label = "1" ]; - f -> b [ label = "0" ]; - f -> h [ label = "1" ]; - g -> i [ label = "0" ]; - g -> g [ label = "1" ]; - h -> i [ label = "0" ]; - h -> h [ label = "1" ]; - i -> i [ label = "0" ]; - i -> j [ label = "1" ]; - j -> i [ label = "0" ]; - j -> h [ label = "1" ]; - } - - - -Drive a FSM -~~~~~~~~~~~ - -There are *lots* of FSM libraries already. Once you have the state -transition table they should all be straightforward to use. State -Machine code is very simple. Just for fun, here is an implementation in -Python that imitates what “compiled” FSM code might look like in an -“unrolled” form. Most FSM code uses a little driver loop and a table -datastructure, the code below instead acts like JMP instructions -(“jump”, or GOTO in higher-level-but-still-low-level languages) to -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. - -.. code:: ipython2 - - 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 - -Stream Functions -^^^^^^^^^^^^^^^^ - -Little helpers to process the iterator of our data (a “stream” of “1” -and “0” characters, not bits.) - -.. code:: ipython2 - - getch = lambda I: int(next(I)) - - - def _1(I): - '''Loop on ones.''' - while getch(I): pass - - - def _0(I): - '''Loop on zeros.''' - while not getch(I): pass - -A Finite State Machine -^^^^^^^^^^^^^^^^^^^^^^ - -With those preliminaries out of the way, from the state table of -``.111. & (.01 + 11*)'`` we can immediately write down state machine -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 - - 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. - -.. code:: ipython2 - - def acceptable(input_): - return trampoline(input_, a, {h, i}) - -.. code:: ipython2 - - for n in range(2**5): - s = bin(n)[2:] - print '%05s' % s, acceptable(s) - - -.. parsed-literal:: - - 0 False - 1 False - 10 False - 11 False - 100 False - 101 False - 110 False - 111 False - 1000 False - 1001 False - 1010 False - 1011 False - 1100 False - 1101 False - 1110 True - 1111 False - 10000 False - 10001 False - 10010 False - 10011 False - 10100 False - 10101 False - 10110 False - 10111 True - 11000 False - 11001 False - 11010 False - 11011 False - 11100 True - 11101 False - 11110 True - 11111 False - - -Reversing the Derivatives to Generate Matching Strings ------------------------------------------------------- - -(UNFINISHED) Brzozowski also shewed how to go from the state machine to -strings and expressions… - -Each of these states is just a name for a Brzozowskian RE, and so, other -than the initial state ``a``, they can can be described in terms of the -derivative-with-respect-to-N of some other state/RE: - -:: - - c = d1(a) - b = d0(a) - b = d0(c) - ... - i = d0(j) - j = d1(i) - -Consider: - -:: - - c = d1(a) - b = d0(c) - -Substituting: - -:: - - b = d0(d1(a)) - -Unwrapping: - -:: - - b = d10(a) - -’’’ - -:: - - j = d1(d0(j)) - -Unwrapping: - -:: - - j = d1(d0(j)) = d01(j) - -We have a loop or “fixed point”. - -:: - - j = d01(j) = d0101(j) = d010101(j) = ... - -hmm… - -:: - - j = (01)* - - diff --git a/docs/sphinx_docs/notebooks/Developing.rst b/docs/sphinx_docs/notebooks/Developing.rst deleted file mode 100644 index 556225a..0000000 --- a/docs/sphinx_docs/notebooks/Developing.rst +++ /dev/null @@ -1,815 +0,0 @@ -*************************** -Developing a Program in Joy -*************************** - -As an example of developing a program in Joy let's take the first problem from the Project Euler website. - -`Project Euler, first problem: "Multiples of 3 and 5" `__ -============================================================================================= - - - 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. - -.. code:: python - - 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. - -.. code:: python - - define('P == [3 % not] dupdip 5 % not or') - -.. code:: python - - V('80 P') - - -.. parsed-literal:: - - . 80 P - 80 . P - 80 . [3 % not] dupdip 5 % not or - 80 [3 % not] . dupdip 5 % not or - 80 . 3 % not 80 5 % not or - 80 3 . % not 80 5 % not or - 2 . not 80 5 % not or - False . 80 5 % not or - False 80 . 5 % not or - False 80 5 . % not or - False 0 . not or - False True . or - True . - - -Given the predicate function ``P`` a suitable program is: - -:: - - PE1 == 1000 range [P] filter sum - -This function generates a list of the integers from 0 to 999, filters -that list by ``P``, and then sums the result. - -Logically this is fine, but pragmatically we are doing more work than we -should be; we generate one thousand integers but actually use less than -half of them. A better solution would be to generate just the multiples -we want to sum, and to add them as we go rather than storing them and -and summing them at the end. - -Generate just the multiples -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -At first I had the idea to use two counters and increase them by three -and five, respectively. This way we only generate the terms that we -actually want to sum. We have to proceed by incrementing the counter -that is lower, or if they are equal, the three counter, and we have to -take care not to double add numbers like 15 that are multiples of both -three and five. - -This seemed a little clunky, so I tried a different approach. - -Consider the first few terms in the series: - -:: - - 3 5 6 9 10 12 15 18 20 21 ... - -Subtract each number from the one after it (subtracting 0 from 3): - -:: - - 3 5 6 9 10 12 15 18 20 21 24 25 27 30 ... - 0 3 5 6 9 10 12 15 18 20 21 24 25 27 ... - ------------------------------------------- - 3 2 1 3 1 2 3 3 2 1 3 1 2 3 ... - -You get this lovely repeating palindromic sequence: - -:: - - 3 2 1 3 1 2 3 - -To make a counter that increments by factors of 3 and 5 you just add -these differences to the counter one-by-one in a loop. - -To make use of this sequence to increment a counter and sum terms as we -go we need a function that will accept the sum, the counter, and the -next term to add, and that adds the term to the counter and a copy of -the counter to the running sum. This function will do that: - -:: - - PE1.1 == + [+] dupdip - -.. code:: python - - define('PE1.1 == + [+] dupdip') - -.. code:: python - - V('0 0 3 PE1.1') - - -.. parsed-literal:: - - . 0 0 3 PE1.1 - 0 . 0 3 PE1.1 - 0 0 . 3 PE1.1 - 0 0 3 . PE1.1 - 0 0 3 . + [+] dupdip - 0 3 . [+] dupdip - 0 3 [+] . dupdip - 0 3 . + 3 - 3 . 3 - 3 3 . - - -.. code:: python - - V('0 0 [3 2 1 3 1 2 3] [PE1.1] step') - - -.. parsed-literal:: - - . 0 0 [3 2 1 3 1 2 3] [PE1.1] step - 0 . 0 [3 2 1 3 1 2 3] [PE1.1] step - 0 0 . [3 2 1 3 1 2 3] [PE1.1] step - 0 0 [3 2 1 3 1 2 3] . [PE1.1] step - 0 0 [3 2 1 3 1 2 3] [PE1.1] . step - 0 0 3 [PE1.1] . i [2 1 3 1 2 3] [PE1.1] step - 0 0 3 . PE1.1 [2 1 3 1 2 3] [PE1.1] step - 0 0 3 . + [+] dupdip [2 1 3 1 2 3] [PE1.1] step - 0 3 . [+] dupdip [2 1 3 1 2 3] [PE1.1] step - 0 3 [+] . dupdip [2 1 3 1 2 3] [PE1.1] step - 0 3 . + 3 [2 1 3 1 2 3] [PE1.1] step - 3 . 3 [2 1 3 1 2 3] [PE1.1] step - 3 3 . [2 1 3 1 2 3] [PE1.1] step - 3 3 [2 1 3 1 2 3] . [PE1.1] step - 3 3 [2 1 3 1 2 3] [PE1.1] . step - 3 3 2 [PE1.1] . i [1 3 1 2 3] [PE1.1] step - 3 3 2 . PE1.1 [1 3 1 2 3] [PE1.1] step - 3 3 2 . + [+] dupdip [1 3 1 2 3] [PE1.1] step - 3 5 . [+] dupdip [1 3 1 2 3] [PE1.1] step - 3 5 [+] . dupdip [1 3 1 2 3] [PE1.1] step - 3 5 . + 5 [1 3 1 2 3] [PE1.1] step - 8 . 5 [1 3 1 2 3] [PE1.1] step - 8 5 . [1 3 1 2 3] [PE1.1] step - 8 5 [1 3 1 2 3] . [PE1.1] step - 8 5 [1 3 1 2 3] [PE1.1] . step - 8 5 1 [PE1.1] . i [3 1 2 3] [PE1.1] step - 8 5 1 . PE1.1 [3 1 2 3] [PE1.1] step - 8 5 1 . + [+] dupdip [3 1 2 3] [PE1.1] step - 8 6 . [+] dupdip [3 1 2 3] [PE1.1] step - 8 6 [+] . dupdip [3 1 2 3] [PE1.1] step - 8 6 . + 6 [3 1 2 3] [PE1.1] step - 14 . 6 [3 1 2 3] [PE1.1] step - 14 6 . [3 1 2 3] [PE1.1] step - 14 6 [3 1 2 3] . [PE1.1] step - 14 6 [3 1 2 3] [PE1.1] . step - 14 6 3 [PE1.1] . i [1 2 3] [PE1.1] step - 14 6 3 . PE1.1 [1 2 3] [PE1.1] step - 14 6 3 . + [+] dupdip [1 2 3] [PE1.1] step - 14 9 . [+] dupdip [1 2 3] [PE1.1] step - 14 9 [+] . dupdip [1 2 3] [PE1.1] step - 14 9 . + 9 [1 2 3] [PE1.1] step - 23 . 9 [1 2 3] [PE1.1] step - 23 9 . [1 2 3] [PE1.1] step - 23 9 [1 2 3] . [PE1.1] step - 23 9 [1 2 3] [PE1.1] . step - 23 9 1 [PE1.1] . i [2 3] [PE1.1] step - 23 9 1 . PE1.1 [2 3] [PE1.1] step - 23 9 1 . + [+] dupdip [2 3] [PE1.1] step - 23 10 . [+] dupdip [2 3] [PE1.1] step - 23 10 [+] . dupdip [2 3] [PE1.1] step - 23 10 . + 10 [2 3] [PE1.1] step - 33 . 10 [2 3] [PE1.1] step - 33 10 . [2 3] [PE1.1] step - 33 10 [2 3] . [PE1.1] step - 33 10 [2 3] [PE1.1] . step - 33 10 2 [PE1.1] . i [3] [PE1.1] step - 33 10 2 . PE1.1 [3] [PE1.1] step - 33 10 2 . + [+] dupdip [3] [PE1.1] step - 33 12 . [+] dupdip [3] [PE1.1] step - 33 12 [+] . dupdip [3] [PE1.1] step - 33 12 . + 12 [3] [PE1.1] step - 45 . 12 [3] [PE1.1] step - 45 12 . [3] [PE1.1] step - 45 12 [3] . [PE1.1] step - 45 12 [3] [PE1.1] . step - 45 12 3 [PE1.1] . i - 45 12 3 . PE1.1 - 45 12 3 . + [+] dupdip - 45 15 . [+] dupdip - 45 15 [+] . dupdip - 45 15 . + 15 - 60 . 15 - 60 15 . - - -So one ``step`` through all seven terms brings the counter to 15 and the -total to 60. - -How many multiples to sum? -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code:: python - - 1000 / 15 - - - - -.. parsed-literal:: - - 66 - - - -.. code:: python - - 66 * 15 - - - - -.. parsed-literal:: - - 990 - - - -.. code:: python - - 1000 - 990 - - - - -.. parsed-literal:: - - 10 - - - -We only want the terms *less than* 1000. - -.. code:: python - - 999 - 990 - - - - -.. parsed-literal:: - - 9 - - - -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:: 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:: python - - J('PE1') - - -.. parsed-literal:: - - 233168 - -Packing the terms into an integer -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This form uses no extra storage and produces no unused summands. It's -good but there's one more trick we can apply. The list of seven terms -takes up at least seven bytes. But notice that all of the terms are less -than four, and so each can fit in just two bits. We could store all -seven terms in just fourteen bits and use masking and shifts to pick out -each term as we go. This will use less space and save time loading whole -integer terms from the list. - -:: - - 3 2 1 3 1 2 3 - 0b 11 10 01 11 01 10 11 == 14811 - -.. code:: python - - 0b11100111011011 - - - - -.. parsed-literal:: - - 14811 - - - -.. code:: python - - define('PE1.2 == [3 & PE1.1] dupdip 2 >>') - -.. code:: python - - V('0 0 14811 PE1.2') - - -.. parsed-literal:: - - . 0 0 14811 PE1.2 - 0 . 0 14811 PE1.2 - 0 0 . 14811 PE1.2 - 0 0 14811 . PE1.2 - 0 0 14811 . [3 & PE1.1] dupdip 2 >> - 0 0 14811 [3 & PE1.1] . dupdip 2 >> - 0 0 14811 . 3 & PE1.1 14811 2 >> - 0 0 14811 3 . & PE1.1 14811 2 >> - 0 0 3 . PE1.1 14811 2 >> - 0 0 3 . + [+] dupdip 14811 2 >> - 0 3 . [+] dupdip 14811 2 >> - 0 3 [+] . dupdip 14811 2 >> - 0 3 . + 3 14811 2 >> - 3 . 3 14811 2 >> - 3 3 . 14811 2 >> - 3 3 14811 . 2 >> - 3 3 14811 2 . >> - 3 3 3702 . - - -.. code:: python - - V('3 3 3702 PE1.2') - - -.. parsed-literal:: - - . 3 3 3702 PE1.2 - 3 . 3 3702 PE1.2 - 3 3 . 3702 PE1.2 - 3 3 3702 . PE1.2 - 3 3 3702 . [3 & PE1.1] dupdip 2 >> - 3 3 3702 [3 & PE1.1] . dupdip 2 >> - 3 3 3702 . 3 & PE1.1 3702 2 >> - 3 3 3702 3 . & PE1.1 3702 2 >> - 3 3 2 . PE1.1 3702 2 >> - 3 3 2 . + [+] dupdip 3702 2 >> - 3 5 . [+] dupdip 3702 2 >> - 3 5 [+] . dupdip 3702 2 >> - 3 5 . + 5 3702 2 >> - 8 . 5 3702 2 >> - 8 5 . 3702 2 >> - 8 5 3702 . 2 >> - 8 5 3702 2 . >> - 8 5 925 . - - -.. code:: python - - V('0 0 14811 7 [PE1.2] times pop') - - -.. parsed-literal:: - - . 0 0 14811 7 [PE1.2] times pop - 0 . 0 14811 7 [PE1.2] times pop - 0 0 . 14811 7 [PE1.2] times pop - 0 0 14811 . 7 [PE1.2] times pop - 0 0 14811 7 . [PE1.2] times pop - 0 0 14811 7 [PE1.2] . times pop - 0 0 14811 [PE1.2] . i 6 [PE1.2] times pop - 0 0 14811 . PE1.2 6 [PE1.2] times pop - 0 0 14811 . [3 & PE1.1] dupdip 2 >> 6 [PE1.2] times pop - 0 0 14811 [3 & PE1.1] . dupdip 2 >> 6 [PE1.2] times pop - 0 0 14811 . 3 & PE1.1 14811 2 >> 6 [PE1.2] times pop - 0 0 14811 3 . & PE1.1 14811 2 >> 6 [PE1.2] times pop - 0 0 3 . PE1.1 14811 2 >> 6 [PE1.2] times pop - 0 0 3 . + [+] dupdip 14811 2 >> 6 [PE1.2] times pop - 0 3 . [+] dupdip 14811 2 >> 6 [PE1.2] times pop - 0 3 [+] . dupdip 14811 2 >> 6 [PE1.2] times pop - 0 3 . + 3 14811 2 >> 6 [PE1.2] times pop - 3 . 3 14811 2 >> 6 [PE1.2] times pop - 3 3 . 14811 2 >> 6 [PE1.2] times pop - 3 3 14811 . 2 >> 6 [PE1.2] times pop - 3 3 14811 2 . >> 6 [PE1.2] times pop - 3 3 3702 . 6 [PE1.2] times pop - 3 3 3702 6 . [PE1.2] times pop - 3 3 3702 6 [PE1.2] . times pop - 3 3 3702 [PE1.2] . i 5 [PE1.2] times pop - 3 3 3702 . PE1.2 5 [PE1.2] times pop - 3 3 3702 . [3 & PE1.1] dupdip 2 >> 5 [PE1.2] times pop - 3 3 3702 [3 & PE1.1] . dupdip 2 >> 5 [PE1.2] times pop - 3 3 3702 . 3 & PE1.1 3702 2 >> 5 [PE1.2] times pop - 3 3 3702 3 . & PE1.1 3702 2 >> 5 [PE1.2] times pop - 3 3 2 . PE1.1 3702 2 >> 5 [PE1.2] times pop - 3 3 2 . + [+] dupdip 3702 2 >> 5 [PE1.2] times pop - 3 5 . [+] dupdip 3702 2 >> 5 [PE1.2] times pop - 3 5 [+] . dupdip 3702 2 >> 5 [PE1.2] times pop - 3 5 . + 5 3702 2 >> 5 [PE1.2] times pop - 8 . 5 3702 2 >> 5 [PE1.2] times pop - 8 5 . 3702 2 >> 5 [PE1.2] times pop - 8 5 3702 . 2 >> 5 [PE1.2] times pop - 8 5 3702 2 . >> 5 [PE1.2] times pop - 8 5 925 . 5 [PE1.2] times pop - 8 5 925 5 . [PE1.2] times pop - 8 5 925 5 [PE1.2] . times pop - 8 5 925 [PE1.2] . i 4 [PE1.2] times pop - 8 5 925 . PE1.2 4 [PE1.2] times pop - 8 5 925 . [3 & PE1.1] dupdip 2 >> 4 [PE1.2] times pop - 8 5 925 [3 & PE1.1] . dupdip 2 >> 4 [PE1.2] times pop - 8 5 925 . 3 & PE1.1 925 2 >> 4 [PE1.2] times pop - 8 5 925 3 . & PE1.1 925 2 >> 4 [PE1.2] times pop - 8 5 1 . PE1.1 925 2 >> 4 [PE1.2] times pop - 8 5 1 . + [+] dupdip 925 2 >> 4 [PE1.2] times pop - 8 6 . [+] dupdip 925 2 >> 4 [PE1.2] times pop - 8 6 [+] . dupdip 925 2 >> 4 [PE1.2] times pop - 8 6 . + 6 925 2 >> 4 [PE1.2] times pop - 14 . 6 925 2 >> 4 [PE1.2] times pop - 14 6 . 925 2 >> 4 [PE1.2] times pop - 14 6 925 . 2 >> 4 [PE1.2] times pop - 14 6 925 2 . >> 4 [PE1.2] times pop - 14 6 231 . 4 [PE1.2] times pop - 14 6 231 4 . [PE1.2] times pop - 14 6 231 4 [PE1.2] . times pop - 14 6 231 [PE1.2] . i 3 [PE1.2] times pop - 14 6 231 . PE1.2 3 [PE1.2] times pop - 14 6 231 . [3 & PE1.1] dupdip 2 >> 3 [PE1.2] times pop - 14 6 231 [3 & PE1.1] . dupdip 2 >> 3 [PE1.2] times pop - 14 6 231 . 3 & PE1.1 231 2 >> 3 [PE1.2] times pop - 14 6 231 3 . & PE1.1 231 2 >> 3 [PE1.2] times pop - 14 6 3 . PE1.1 231 2 >> 3 [PE1.2] times pop - 14 6 3 . + [+] dupdip 231 2 >> 3 [PE1.2] times pop - 14 9 . [+] dupdip 231 2 >> 3 [PE1.2] times pop - 14 9 [+] . dupdip 231 2 >> 3 [PE1.2] times pop - 14 9 . + 9 231 2 >> 3 [PE1.2] times pop - 23 . 9 231 2 >> 3 [PE1.2] times pop - 23 9 . 231 2 >> 3 [PE1.2] times pop - 23 9 231 . 2 >> 3 [PE1.2] times pop - 23 9 231 2 . >> 3 [PE1.2] times pop - 23 9 57 . 3 [PE1.2] times pop - 23 9 57 3 . [PE1.2] times pop - 23 9 57 3 [PE1.2] . times pop - 23 9 57 [PE1.2] . i 2 [PE1.2] times pop - 23 9 57 . PE1.2 2 [PE1.2] times pop - 23 9 57 . [3 & PE1.1] dupdip 2 >> 2 [PE1.2] times pop - 23 9 57 [3 & PE1.1] . dupdip 2 >> 2 [PE1.2] times pop - 23 9 57 . 3 & PE1.1 57 2 >> 2 [PE1.2] times pop - 23 9 57 3 . & PE1.1 57 2 >> 2 [PE1.2] times pop - 23 9 1 . PE1.1 57 2 >> 2 [PE1.2] times pop - 23 9 1 . + [+] dupdip 57 2 >> 2 [PE1.2] times pop - 23 10 . [+] dupdip 57 2 >> 2 [PE1.2] times pop - 23 10 [+] . dupdip 57 2 >> 2 [PE1.2] times pop - 23 10 . + 10 57 2 >> 2 [PE1.2] times pop - 33 . 10 57 2 >> 2 [PE1.2] times pop - 33 10 . 57 2 >> 2 [PE1.2] times pop - 33 10 57 . 2 >> 2 [PE1.2] times pop - 33 10 57 2 . >> 2 [PE1.2] times pop - 33 10 14 . 2 [PE1.2] times pop - 33 10 14 2 . [PE1.2] times pop - 33 10 14 2 [PE1.2] . times pop - 33 10 14 [PE1.2] . i 1 [PE1.2] times pop - 33 10 14 . PE1.2 1 [PE1.2] times pop - 33 10 14 . [3 & PE1.1] dupdip 2 >> 1 [PE1.2] times pop - 33 10 14 [3 & PE1.1] . dupdip 2 >> 1 [PE1.2] times pop - 33 10 14 . 3 & PE1.1 14 2 >> 1 [PE1.2] times pop - 33 10 14 3 . & PE1.1 14 2 >> 1 [PE1.2] times pop - 33 10 2 . PE1.1 14 2 >> 1 [PE1.2] times pop - 33 10 2 . + [+] dupdip 14 2 >> 1 [PE1.2] times pop - 33 12 . [+] dupdip 14 2 >> 1 [PE1.2] times pop - 33 12 [+] . dupdip 14 2 >> 1 [PE1.2] times pop - 33 12 . + 12 14 2 >> 1 [PE1.2] times pop - 45 . 12 14 2 >> 1 [PE1.2] times pop - 45 12 . 14 2 >> 1 [PE1.2] times pop - 45 12 14 . 2 >> 1 [PE1.2] times pop - 45 12 14 2 . >> 1 [PE1.2] times pop - 45 12 3 . 1 [PE1.2] times pop - 45 12 3 1 . [PE1.2] times pop - 45 12 3 1 [PE1.2] . times pop - 45 12 3 [PE1.2] . i pop - 45 12 3 . PE1.2 pop - 45 12 3 . [3 & PE1.1] dupdip 2 >> pop - 45 12 3 [3 & PE1.1] . dupdip 2 >> pop - 45 12 3 . 3 & PE1.1 3 2 >> pop - 45 12 3 3 . & PE1.1 3 2 >> pop - 45 12 3 . PE1.1 3 2 >> pop - 45 12 3 . + [+] dupdip 3 2 >> pop - 45 15 . [+] dupdip 3 2 >> pop - 45 15 [+] . dupdip 3 2 >> pop - 45 15 . + 15 3 2 >> pop - 60 . 15 3 2 >> pop - 60 15 . 3 2 >> pop - 60 15 3 . 2 >> pop - 60 15 3 2 . >> pop - 60 15 0 . pop - 60 15 . - - -And so we have at last: - -.. code:: python - - define('PE1 == 0 0 66 [14811 7 [PE1.2] times pop] times 14811 4 [PE1.2] times popop') - -.. code:: python - - J('PE1') - - -.. parsed-literal:: - - 233168 - - -Let's refactor -^^^^^^^^^^^^^^^ - -:: - - 14811 7 [PE1.2] times pop - 14811 4 [PE1.2] times pop - 14811 n [PE1.2] times pop - n 14811 swap [PE1.2] times pop - -.. code:: python - - define('PE1.3 == 14811 swap [PE1.2] times pop') - -Now we can simplify the definition above: - -.. code:: python - - define('PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop') - -.. code:: python - - J('PE1') - - -.. parsed-literal:: - - 233168 - - -Here's our joy program all in one place. It doesn't make so much sense, -but if you have read through the above description of how it was derived -I hope it's clear. - -:: - - PE1.1 == + [+] dupdip - PE1.2 == [3 & PE1.1] dupdip 2 >> - PE1.3 == 14811 swap [PE1.2] times pop - PE1 == 0 0 66 [7 PE1.3] times 4 PE1.3 pop - -Generator Version -================= - -It's a little clunky iterating sixty-six times though the seven numbers -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:: python - - define('PE1.terms == [0 swap [dup [pop 14811] [] branch [3 &] dupdip 2 >>] dip rest cons]') - -.. code:: python - - J('PE1.terms 21 [x] times') - - -.. parsed-literal:: - - 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] - - -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:: python - - J('7 66 * 4 +') - - -.. parsed-literal:: - - 466 - - -Here they are... -~~~~~~~~~~~~~~~~ - -.. code:: python - - J('PE1.terms 466 [x] times pop') - - -.. parsed-literal:: - - 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 - - -...and they do sum to 999. -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code:: python - - J('[PE1.terms 466 [x] times pop] run sum') - - -.. parsed-literal:: - - 999 - - -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:: python - - J('0 0 PE1.terms 466 [x [PE1.1] dip] times popop') - - -.. parsed-literal:: - - 233168 - - -A little further analysis renders iteration unnecessary. -======================================================== - -Consider finding the sum of the positive integers less than or equal to -ten. - -.. code:: python - - J('[10 9 8 7 6 5 4 3 2 1] sum') - - -.. parsed-literal:: - - 55 - - -Instead of summing them, -`observe `__: - -:: - - 10 9 8 7 6 - + 1 2 3 4 5 - ---- -- -- -- -- - 11 11 11 11 11 - - 11 * 5 = 55 - -From the above example we can deduce that the sum of the first N -positive integers is: - -:: - - (N + 1) * N / 2 - -(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:: python - - define('F == dup ++ * 2 floordiv') - -.. code:: python - - V('10 F') - - -.. parsed-literal:: - - . 10 F - 10 . F - 10 . dup ++ * 2 floordiv - 10 10 . ++ * 2 floordiv - 10 11 . * 2 floordiv - 110 . 2 floordiv - 110 2 . floordiv - 55 . - - -Generalizing to Blocks of Terms -------------------------------- - -We can apply the same reasoning to the PE1 problem. - -Between 0 and 990 inclusive there are sixty-six "blocks" of seven terms -each, starting with: - -:: - - [3 5 6 9 10 12 15] - -And ending with: - -:: - - [978 980 981 984 985 987 990] - -If we reverse one of these two blocks and sum pairs... - -.. code:: python - - J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip') - - -.. parsed-literal:: - - [[978 15] [980 12] [981 10] [984 9] [985 6] [987 5] [990 3]] - - -.. code:: python - - J('[3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map') - - -.. parsed-literal:: - - [993 992 991 993 991 992 993] - - -(Interesting that the sequence of seven numbers appears again in the -rightmost digit of each term.) - -.. code:: python - - J('[ 3 5 6 9 10 12 15] reverse [978 980 981 984 985 987 990] zip [sum] map sum') - - -.. parsed-literal:: - - 6945 - - -Since there are sixty-six blocks and we are pairing them up, there must -be thirty-three pairs, each of which sums to 6945. We also have these -additional unpaired terms between 990 and 1000: - -:: - - 993 995 996 999 - -So we can give the "sum of all the multiples of 3 or 5 below 1000" like -so: - -.. code:: python - - J('6945 33 * [993 995 996 999] cons sum') - - -.. parsed-literal:: - - 233168 - - -It's worth noting, I think, that this same reasoning holds for any two -numbers :math:`n` and :math:`m` the multiples of which we hope to sum. -The multiples would have a cycle of differences of length :math:`k` and -so we could compute the sum of :math:`Nk` multiples as above. - -The sequence of differences will always be a palidrome. Consider an -interval spanning the least common multiple of :math:`n` and :math:`m`: - -:: - - | | | | | | | | - | | | | | - -Here we have 4 and 7, and you can read off the sequence of differences -directly from the diagram: 4 3 1 4 2 2 4 1 3 4. - -Geometrically, the actual values of :math:`n` and :math:`m` and their -*lcm* don't matter, the pattern they make will always be symmetrical -around its midpoint. The same reasoning holds for multiples of more than -two numbers. - -The Simplest Program -==================== - -Of course, the simplest joy program for the first Project Euler problem -is just: - -:: - - PE1 == 233168 - -Fin. diff --git a/docs/sphinx_docs/notebooks/Generator_Programs.rst b/docs/sphinx_docs/notebooks/Generator_Programs.rst deleted file mode 100644 index 55e1679..0000000 --- a/docs/sphinx_docs/notebooks/Generator_Programs.rst +++ /dev/null @@ -1,635 +0,0 @@ -Using ``x`` to Generate Values -============================== - -Cf. jp-reprod.html - -.. code:: ipython2 - - from notebook_preamble import J, V, define - -Consider the ``x`` combinator: - -:: - - x == dup i - -We can apply it to a quoted program consisting of some value ``a`` and -some function ``B``: - -:: - - [a B] x - [a B] a B - -Let ``B`` function ``swap`` the ``a`` with the quote and run some -function ``C`` on it to generate a new value ``b``: - -:: - - B == swap [C] dip - - [a B] a B - [a B] a swap [C] dip - a [a B] [C] dip - a C [a B] - b [a B] - -Now discard the quoted ``a`` with ``rest`` then ``cons`` ``b``: - -:: - - b [a B] rest cons - b [B] cons - [b B] - -Altogether, this is the definition of ``B``: - -:: - - B == swap [C] dip rest cons - -We can make a generator for the Natural numbers (0, 1, 2, …) by using -``0`` for ``a`` and ``[dup ++]`` for ``[C]``: - -:: - - [0 swap [dup ++] dip rest cons] - -Let’s try it: - -.. code:: ipython2 - - V('[0 swap [dup ++] dip rest cons] x') - - -.. parsed-literal:: - - . [0 swap [dup ++] dip rest cons] x - [0 swap [dup ++] dip rest cons] . x - [0 swap [dup ++] dip rest cons] . 0 swap [dup ++] dip rest cons - [0 swap [dup ++] dip rest cons] 0 . swap [dup ++] dip rest cons - 0 [0 swap [dup ++] dip rest cons] . [dup ++] dip rest cons - 0 [0 swap [dup ++] dip rest cons] [dup ++] . dip rest cons - 0 . dup ++ [0 swap [dup ++] dip rest cons] rest cons - 0 0 . ++ [0 swap [dup ++] dip rest cons] rest cons - 0 1 . [0 swap [dup ++] dip rest cons] rest cons - 0 1 [0 swap [dup ++] dip rest cons] . rest cons - 0 1 [swap [dup ++] dip rest cons] . cons - 0 [1 swap [dup ++] dip rest cons] . - - -After one application of ``x`` the quoted program contains ``1`` and -``0`` is below it on the stack. - -.. code:: ipython2 - - J('[0 swap [dup ++] dip rest cons] x x x x x pop') - - -.. parsed-literal:: - - 0 1 2 3 4 - - -``direco`` ----------- - -.. code:: ipython2 - - define('direco == dip rest cons') - -.. code:: ipython2 - - V('[0 swap [dup ++] direco] x') - - -.. parsed-literal:: - - . [0 swap [dup ++] direco] x - [0 swap [dup ++] direco] . x - [0 swap [dup ++] direco] . 0 swap [dup ++] direco - [0 swap [dup ++] direco] 0 . swap [dup ++] direco - 0 [0 swap [dup ++] direco] . [dup ++] direco - 0 [0 swap [dup ++] direco] [dup ++] . direco - 0 [0 swap [dup ++] direco] [dup ++] . dip rest cons - 0 . dup ++ [0 swap [dup ++] direco] rest cons - 0 0 . ++ [0 swap [dup ++] direco] rest cons - 0 1 . [0 swap [dup ++] direco] rest cons - 0 1 [0 swap [dup ++] direco] . rest cons - 0 1 [swap [dup ++] direco] . cons - 0 [1 swap [dup ++] direco] . - - -Making Generators ------------------ - -We want to define a function that accepts ``a`` and ``[C]`` and builds -our quoted program: - -:: - - a [C] G - ------------------------- - [a swap [C] direco] - -Working in reverse: - -:: - - [a swap [C] direco] cons - a [swap [C] direco] concat - a [swap] [[C] direco] swap - a [[C] direco] [swap] - a [C] [direco] cons [swap] - -Reading from the bottom up: - -:: - - G == [direco] cons [swap] swap concat cons - G == [direco] cons [swap] swoncat cons - -.. code:: ipython2 - - define('G == [direco] cons [swap] swoncat cons') - -Let’s try it out: - -.. code:: ipython2 - - J('0 [dup ++] G') - - -.. parsed-literal:: - - [0 swap [dup ++] direco] - - -.. code:: ipython2 - - J('0 [dup ++] G x x x pop') - - -.. parsed-literal:: - - 0 1 2 - - -Powers of 2 -~~~~~~~~~~~ - -.. code:: ipython2 - - J('1 [dup 1 <<] G x x x x x x x x x pop') - - -.. parsed-literal:: - - 1 2 4 8 16 32 64 128 256 - - -``[x] times`` -~~~~~~~~~~~~~ - -If we have one of these quoted programs we can drive it using ``times`` -with the ``x`` combinator. - -.. code:: ipython2 - - J('23 [dup ++] G 5 [x] times') - - -.. parsed-literal:: - - 23 24 25 26 27 [28 swap [dup ++] direco] - - -Generating Multiples of Three and Five --------------------------------------- - -Look at the treatment of the Project Euler Problem One in the -“Developing a Program” notebook and you’ll see that we might be -interested in generating an endless cycle of: - -:: - - 3 2 1 3 1 2 3 - -To do this we want to encode the numbers as pairs of bits in a single -int: - -:: - - 3 2 1 3 1 2 3 - 0b 11 10 01 11 01 10 11 == 14811 - -And pick them off by masking with 3 (binary 11) and then shifting the -int right two bits. - -.. code:: ipython2 - - define('PE1.1 == dup [3 &] dip 2 >>') - -.. code:: ipython2 - - V('14811 PE1.1') - - -.. parsed-literal:: - - . 14811 PE1.1 - 14811 . PE1.1 - 14811 . dup [3 &] dip 2 >> - 14811 14811 . [3 &] dip 2 >> - 14811 14811 [3 &] . dip 2 >> - 14811 . 3 & 14811 2 >> - 14811 3 . & 14811 2 >> - 3 . 14811 2 >> - 3 14811 . 2 >> - 3 14811 2 . >> - 3 3702 . - - -If we plug ``14811`` and ``[PE1.1]`` into our generator form… - -.. code:: ipython2 - - J('14811 [PE1.1] G') - - -.. parsed-literal:: - - [14811 swap [PE1.1] direco] - - -…we get a generator that works for seven cycles before it reaches zero: - -.. code:: ipython2 - - J('[14811 swap [PE1.1] direco] 7 [x] times') - - -.. parsed-literal:: - - 3 2 1 3 1 2 3 [0 swap [PE1.1] direco] - - -Reset at Zero -~~~~~~~~~~~~~ - -We need a function that checks if the int has reached zero and resets it -if so. - -.. code:: ipython2 - - define('PE1.1.check == dup [pop 14811] [] branch') - -.. code:: ipython2 - - J('14811 [PE1.1.check PE1.1] G') - - -.. parsed-literal:: - - [14811 swap [PE1.1.check PE1.1] direco] - - -.. code:: ipython2 - - J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times') - - -.. parsed-literal:: - - 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] - - -(It would be more efficient to reset the int every seven cycles but -that’s a little beyond the scope of this article. This solution does -extra work, but not much, and we’re not using it “in production” as they -say.) - -Run 466 times -~~~~~~~~~~~~~ - -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 - - J('7 66 * 4 +') - - -.. parsed-literal:: - - 466 - - -If we drive our generator 466 times and sum the stack we get 999. - -.. code:: ipython2 - - J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times') - - -.. parsed-literal:: - - 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 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 - - J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum') - - -.. parsed-literal:: - - 999 - - -Project Euler Problem One -------------------------- - -.. code:: ipython2 - - define('PE1.2 == + dup [+] dip') - -Now we can add ``PE1.2`` to the quoted program given to ``G``. - -.. code:: ipython2 - - J('0 0 0 [PE1.1.check PE1.1] G 466 [x [PE1.2] dip] times popop') - - -.. parsed-literal:: - - 233168 - - -A generator for the Fibonacci Sequence. ---------------------------------------- - -Consider: - -:: - - [b a F] x - [b a F] b a F - -The obvious first thing to do is just add ``b`` and ``a``: - -:: - - [b a F] b a + - [b a F] b+a - -From here we want to arrive at: - -:: - - b [b+a b F] - -Let’s start with ``swons``: - -:: - - [b a F] b+a swons - [b+a b a F] - -Considering this quote as a stack: - -:: - - F a b b+a - -We want to get it to: - -:: - - F b b+a b - -So: - -:: - - F a b b+a popdd over - F b b+a b - -And therefore: - -:: - - [b+a b a F] [popdd over] infra - [b b+a b F] - -But we can just use ``cons`` to carry ``b+a`` into the quote: - -:: - - [b a F] b+a [popdd over] cons infra - [b a F] [b+a popdd over] infra - [b b+a b F] - -Lastly: - -:: - - [b b+a b F] uncons - b [b+a b F] - -Putting it all together: - -:: - - F == + [popdd over] cons infra uncons - fib_gen == [1 1 F] - -.. code:: ipython2 - - define('fib == + [popdd over] cons infra uncons') - -.. code:: ipython2 - - define('fib_gen == [1 1 fib]') - -.. code:: ipython2 - - J('fib_gen 10 [x] times') - - -.. parsed-literal:: - - 1 2 3 5 8 13 21 34 55 89 [144 89 fib] - - -Project Euler Problem Two -------------------------- - - By considering the terms in the Fibonacci sequence whose values do - 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 -``pop``\ s it otherwise. - -.. code:: ipython2 - - define('PE2.1 == dup 2 % [+] [pop] branch') - -And a predicate function that detects when the terms in the series -“exceed four million”. - -.. code:: ipython2 - - 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. - -.. code:: ipython2 - - define('PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec') - -.. code:: ipython2 - - J('PE2') - - -.. parsed-literal:: - - 4613732 - - -Here’s the collected program definitions: - -:: - - fib == + swons [popdd over] infra uncons - fib_gen == [1 1 fib] - - even == dup 2 % - >4M == 4000000 > - - PE2.1 == even [+] [pop] branch - PE2 == 0 fib_gen x [pop >4M] [popop] [[PE2.1] dip x] primrec - -Even-valued Fibonacci Terms -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Using ``o`` for odd and ``e`` for even: - -:: - - o + o = e - e + e = e - o + e = o - -So the Fibonacci sequence considered in terms of just parity would be: - -:: - - o o e o o e o o e o o e o o e o o e - 1 1 2 3 5 8 . . . - -Every third term is even. - -.. code:: ipython2 - - J('[1 0 fib] x x x') # To start the sequence with 1 1 2 3 instead of 1 2 3. - - -.. parsed-literal:: - - 1 1 2 [3 2 fib] - - -Drive the generator three times and ``popop`` the two odd terms. - -.. code:: ipython2 - - J('[1 0 fib] x x x [popop] dipd') - - -.. parsed-literal:: - - 2 [3 2 fib] - - -.. code:: ipython2 - - define('PE2.2 == x x x [popop] dipd') - -.. code:: ipython2 - - J('[1 0 fib] 10 [PE2.2] times') - - -.. parsed-literal:: - - 2 8 34 144 610 2584 10946 46368 196418 832040 [1346269 832040 fib] - - -Replace ``x`` with our new driver function ``PE2.2`` and start our -``fib`` generator at ``1 0``. - -.. code:: ipython2 - - J('0 [1 0 fib] PE2.2 [pop >4M] [popop] [[PE2.1] dip PE2.2] primrec') - - -.. parsed-literal:: - - 4613732 - - -How to compile these? ---------------------- - -You would probably start with a special version of ``G``, and perhaps -modifications to the default ``x``? - -An Interesting Variation ------------------------- - -.. code:: ipython2 - - define('codireco == cons dip rest cons') - -.. code:: ipython2 - - V('[0 [dup ++] codireco] x') - - -.. parsed-literal:: - - . [0 [dup ++] codireco] x - [0 [dup ++] codireco] . x - [0 [dup ++] codireco] . 0 [dup ++] codireco - [0 [dup ++] codireco] 0 . [dup ++] codireco - [0 [dup ++] codireco] 0 [dup ++] . codireco - [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons - [0 [dup ++] codireco] [0 dup ++] . dip rest cons - . 0 dup ++ [0 [dup ++] codireco] rest cons - 0 . dup ++ [0 [dup ++] codireco] rest cons - 0 0 . ++ [0 [dup ++] codireco] rest cons - 0 1 . [0 [dup ++] codireco] rest cons - 0 1 [0 [dup ++] codireco] . rest cons - 0 1 [[dup ++] codireco] . cons - 0 [1 [dup ++] codireco] . - - -.. code:: ipython2 - - define('G == [codireco] cons cons') - -.. code:: ipython2 - - J('230 [dup ++] G 5 [x] times pop') - - -.. parsed-literal:: - - 230 231 232 233 234 - diff --git a/docs/sphinx_docs/notebooks/Intro.rst b/docs/sphinx_docs/notebooks/Intro.rst deleted file mode 100644 index 73704cf..0000000 --- a/docs/sphinx_docs/notebooks/Intro.rst +++ /dev/null @@ -1,335 +0,0 @@ - -******************* -Thun: Joy in Python -******************* - -This implementation is meant as a tool for exploring the programming -model and method of Joy. Python seems like a great implementation -language for Joy for several reasons. - -* We can lean on the Python immutable types for our basic semantics and types: ints, floats, strings, and tuples, which enforces functional purity. -* We get garbage collection for free. -* Compilation via Cython. -* Python is a "glue language" with loads of libraries which we can wrap in Joy functions. - - -`Read-Eval-Print Loop (REPL) `__ -==================================================================================================== - -The main way to interact with the Joy interpreter is through a simple -`REPL `__ -that you start by running the package: - -:: - - $ python3 -m joy - Thun - Copyright © 2017 Simon Forman - This program comes with ABSOLUTELY NO WARRANTY; for details type "warranty". - This is free software, and you are welcome to redistribute it - under certain conditions; type "sharing" for details. - Type "words" to see a list of all words, and "[] help" to print the - docs for a word. - - - <-top - - joy? _ - -The ``<-top`` marker points to the top of the (initially empty) stack. -You can enter Joy notation at the prompt and a :doc:`trace of evaluation <../pretty>` will -be printed followed by the stack and prompt again:: - - joy? 23 sqr 18 + - - 547 <-top - - joy? - -There is a `trace` combinator:: - - joy? 23 [sqr 18 +] trace - 23 . sqr 18 + - 23 . dup mul 18 + - 23 23 . mul 18 + - 529 . 18 + - 529 18 . + - 547 . - - 547 <-top - - joy? - - -The Stack -============= - -In Joy, in addition to the types Boolean, integer, float, and string, -there is a :doc:`single sequence type <../stack>` represented by enclosing a sequence of -terms in brackets ``[...]``. This sequence type is used to represent -both the stack and the expression. It is a `cons -list `__ made from Python -tuples. - - -Purely Functional Datastructures -================================= - -Because Joy stacks are made out of Python tuples they are immutable, as are the other Python types we "borrow" for Joy, so all Joy datastructures are `purely functional `__. - - -The ``joy()`` function -======================= - -An Interpreter -~~~~~~~~~~~~~~~~~ - -The ``joy()`` interpreter function is extrememly simple. It accepts a stack, an -expression, and a dictionary, and it iterates through the expression -putting values onto the stack and delegating execution to functions which it -looks up in the dictionary. - - -`Continuation-Passing Style `__ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -One day I thought, What happens if you rewrite Joy to use -`CPS `__? I -made all the functions accept and return the expression as well as the -stack and found that all the combinators could be rewritten to work by -modifying the expression rather than making recursive calls to the -``joy()`` function. - - -View function -~~~~~~~~~~~~~ - -The ``joy()`` function accepts an optional ``viewer`` argument that -is a function which it calls on -each iteration passing the current stack and expression just before -evaluation. This can be used for tracing, breakpoints, retrying after -exceptions, or interrupting an evaluation and saving to disk or sending -over the network to resume later. The stack and expression together -contain all the state of the computation at each step. - - -The ``TracePrinter``. -~~~~~~~~~~~~~~~~~~~~~ - -A ``viewer`` records each step of the evaluation of a Joy program. The -``TracePrinter`` has a facility for printing out a trace of the -evaluation, one line per step. Each step is aligned to the current -interpreter position, signified by a period separating the stack on the -left from the pending expression ("continuation") on the right. - - -Parser -====== - -The parser is extremely simple. The undocumented ``re.Scanner`` class -does the tokenizing and then the parser builds the tuple -structure out of the tokens. There's no Abstract Syntax Tree or anything -like that. - - -Symbols -~~~~~~~~~~~~~ - -TODO: Symbols are just a string subclass; used by the parser to represent function names and by the interpreter to look up functions in the dictionary. N.B.: Symbols are not looked up at parse-time. You *could* define recursive functions, er, recusively, without ``genrec`` or other recursion combinators ``foo == ... foo ...`` but don't do that. - - -Token Regular Expressions -~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - 123 1.2 'single quotes' "double quotes" function - -TBD (look in the :module: joy.parser module.) - - -Examples -~~~~~~~~~~~ - -.. code:: python - - joy.parser.text_to_expression('1 2 3 4 5') # A simple sequence. - - -.. parsed-literal:: - - (1, (2, (3, (4, (5, ()))))) - - -.. code:: python - - joy.parser.text_to_expression('[1 2 3] 4 5') # Three items, the first is a list with three items - - -.. parsed-literal:: - - ((1, (2, (3, ()))), (4, (5, ()))) - - -.. code:: python - - 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. - - - -.. parsed-literal:: - - (1, (23, (('four', ((-5.0, ()), (cons, ()))), (8888, ())))) - - - -.. code:: python - - joy.parser.text_to_expression('[][][][][]') # Five empty lists. - - - - -.. parsed-literal:: - - ((), ((), ((), ((), ((), ()))))) - - - -.. code:: python - - joy.parser.text_to_expression('[[[[[]]]]]') # Five nested lists. - - - - -.. parsed-literal:: - - ((((((), ()), ()), ()), ()), ()) - - - -Library -======= - -The Joy library of functions (aka commands, or "words" after Forth -usage) encapsulates all the actual functionality (no pun intended) of -the Joy system. There are simple functions such as addition ``add`` (or -``+``, 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``: - -.. code:: python - - print inspect.getsource(joy.library.dip) - - -.. parsed-literal:: - - def dip(stack, expression, dictionary): - (quote, (x, stack)) = stack - expression = x, expression - return stack, concat(quote, expression), dictionary - - -Some functions are defined in equations in terms of other functions. -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:: python - - print joy.library.definitions - - -.. parsed-literal:: - - second == rest first - third == rest rest first - product == 1 swap [*] step - swons == swap cons - swoncat == swap concat - flatten == [] swap [concat] step - unit == [] cons - quoted == [unit] dip - unquoted == [i] dip - enstacken == stack [clear] dip - disenstacken == ? [uncons ?] loop pop - ? == dup truthy - dinfrirst == dip infra first - nullary == [stack] dinfrirst - unary == [stack [pop] dip] dinfrirst - binary == [stack [popop] dip] dinfrirst - ternary == [stack [popop pop] dip] dinfrirst - pam == [i] map - run == [] swap infra - sqr == dup mul - size == 0 swap [pop ++] step - cleave == [i] app2 [popd] dip - average == [sum 1.0 *] [size] cleave / - gcd == 1 [tuck modulus dup 0 >] loop pop - least_fraction == dup [gcd] infra [div] concat map - *fraction == [uncons] dip uncons [swap] dip concat [*] infra [*] dip cons - *fraction0 == concat [[swap] dip * [*] dip] infra - down_to_zero == [0 >] [dup --] while - range_to_zero == unit [down_to_zero] infra - anamorphism == [pop []] swap [dip swons] genrec - range == [0 <=] [1 - dup] anamorphism - while == swap [nullary] cons dup dipd concat loop - dudipd == dup dipd - primrec == [i] genrec - - - -Currently, there's no function to add new definitions to the dictionary -from "within" Joy code itself. Adding new definitions remains a -meta-interpreter action. You have to do it yourself, in Python, and wash -your hands afterward. - -It would be simple enough to define one, but it would open the door to -*name binding* and break the idea that all state is captured in the -stack and expression. There's an implicit *standard dictionary* that -defines the actual semantics of the syntactic stack and expression -datastructures (which only contain symbols, not the actual functions. -Pickle some and see for yourself.) - -"There should be only one." -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Which brings me to talking about one of my hopes and dreams for this -notation: "There should be only one." What I mean is that there should -be one universal standard dictionary of commands, and all bespoke work -done in a UI for purposes takes place by direct interaction and macros. -There would be a *Grand Refactoring* biannually (two years, not six -months, that's semi-annually) where any new definitions factored out of -the usage and macros of the previous time, along with new algorithms and -such, were entered into the dictionary and posted to e.g. IPFS. - -Code should not burgeon wildly, as it does today. The variety of code -should map more-or-less to the well-factored variety of human -computably-solvable problems. There shouldn't be dozens of chat apps, JS -frameworks, programming languages. It's a waste of time, a `fractal -"thundering herd" -attack `__ on -human mentality. - -Literary Code Library -~~~~~~~~~~~~~~~~~~~~~ - -If you read over the other notebooks you'll see that developing code in -Joy is a lot like doing simple mathematics, and the descriptions of the -code resemble math papers. The code also works the first time, no bugs. -If you have any experience programming at all, you are probably -skeptical, as I was, but it seems to work: deriving code mathematically -seems to lead to fewer errors. - -But my point now is that this great ratio of textual explanation to wind -up with code that consists of a few equations and could fit on an index -card is highly desirable. Less code has fewer errors. The structure of -Joy engenders a kind of thinking that seems to be very effective for -developing structured processes. - -There seems to be an elegance and power to the notation. - diff --git a/docs/sphinx_docs/notebooks/Newton-Raphson.rst b/docs/sphinx_docs/notebooks/Newton-Raphson.rst deleted file mode 100644 index cb3f759..0000000 --- a/docs/sphinx_docs/notebooks/Newton-Raphson.rst +++ /dev/null @@ -1,257 +0,0 @@ -`Newton's method `__ -===================================================================== - -Let's use the Newton-Raphson method for finding the root of an equation -to write a function that can compute the square root of a number. - -Cf. `"Why Functional Programming Matters" by John -Hughes `__ - -.. code:: ipython3 - - from notebook_preamble import J, V, define - -A Generator for Approximations ------------------------------- - -To make a generator that generates successive approximations let’s start -by assuming an initial approximation and then derive the function that -computes the next approximation: - -:: - - a F - --------- - a' - -A Function to Compute the Next Approximation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This is the equation for computing the next approximate value of the -square root: - -:math:`a_{i+1} = \frac{(a_i+\frac{n}{a_i})}{2}` - -:: - - a n over / + 2 / - a n a / + 2 / - a n/a + 2 / - a+n/a 2 / - (a+n/a)/2 - -The function we want has the argument ``n`` in it: - -:: - - F == n over / + 2 / - -Make it into a Generator -~~~~~~~~~~~~~~~~~~~~~~~~ - -Our generator would be created by: - -:: - - a [dup F] make_generator - -With n as part of the function F, but n is the input to the sqrt -function we’re writing. If we let 1 be the initial approximation: - -:: - - 1 n 1 / + 2 / - 1 n/1 + 2 / - 1 n + 2 / - n+1 2 / - (n+1)/2 - -The generator can be written as: - -:: - - 23 1 swap [over / + 2 /] cons [dup] swoncat make_generator - 1 23 [over / + 2 /] cons [dup] swoncat make_generator - 1 [23 over / + 2 /] [dup] swoncat make_generator - 1 [dup 23 over / + 2 /] make_generator - -.. code:: ipython3 - - define('gsra 1 swap [over / + 2 /] cons [dup] swoncat make_generator') - -.. code:: ipython3 - - J('23 gsra') - - -.. parsed-literal:: - - [1 [dup 23 over / + 2 /] codireco] - - -Let's drive the generator a few time (with the ``x`` combinator) and -square the approximation to see how well it works... - -.. code:: ipython3 - - J('23 gsra 6 [x popd] times first sqr') - - -.. parsed-literal:: - - 23.0000000001585 - - -Finding Consecutive Approximations within a Tolerance ------------------------------------------------------ - -From `"Why Functional Programming Matters" by John -Hughes `__: - - The remainder of a square root finder is a function *within*, which - takes a tolerance and a list of approximations and looks down the - list for two successive approximations that differ by no more than - the given tolerance. - -(And note that by “list” he means a lazily-evaluated list.) - -Using the *output* ``[a G]`` of the above generator for square root -approximations, and further assuming that the first term a has been -generated already and epsilon ε is handy on the stack... - -:: - - a [b G] ε within - ---------------------- a b - abs ε <= - b - - - a [b G] ε within - ---------------------- a b - abs ε > - b [c G] ε within - -Predicate -~~~~~~~~~ - -:: - - a [b G] ε [first - abs] dip <= - a [b G] first - abs ε <= - a b - abs ε <= - a-b abs ε <= - abs(a-b) ε <= - (abs(a-b)<=ε) - -.. code:: ipython3 - - define('_within_P [first - abs] dip <=') - -Base-Case -~~~~~~~~~ - -:: - - a [b G] ε roll< popop first - [b G] ε a popop first - [b G] first - b - -.. code:: ipython3 - - define('_within_B roll< popop first') - -Recur -~~~~~ - -:: - - a [b G] ε R0 [within] R1 - -1. Discard a. -2. Use ``x`` combinator to generate next term from ``G``. -3. Run ``within`` with ``i`` (it is a "tail-recursive" function.) - -Pretty straightforward: - -:: - - a [b G] ε R0 [within] R1 - a [b G] ε [popd x] dip [within] i - a [b G] popd x ε [within] i - [b G] x ε [within] i - b [c G] ε [within] i - b [c G] ε within - - b [c G] ε within - -.. code:: ipython3 - - define('_within_R [popd x] dip') - -Setting up -~~~~~~~~~~ - -The recursive function we have defined so far needs a slight preamble: -``x`` to prime the generator and the epsilon value to use: - -:: - - [a G] x ε ... - a [b G] ε ... - -.. code:: ipython3 - - define('within x 0.000000001 [_within_P] [_within_B] [_within_R] tailrec') - define('sqrt gsra within') - -Try it out... - -.. code:: ipython3 - - J('36 sqrt') - - -.. parsed-literal:: - - 6.0 - - -.. code:: ipython3 - - J('23 sqrt') - - -.. parsed-literal:: - - 4.795831523312719 - - -Check it. - -.. code:: ipython3 - - 4.795831523312719**2 - - - - -.. parsed-literal:: - - 22.999999999999996 - - - -.. code:: ipython3 - - from math import sqrt - - sqrt(23) - - - - -.. parsed-literal:: - - 4.795831523312719 - - diff --git a/docs/sphinx_docs/notebooks/NoUpdates.rst b/docs/sphinx_docs/notebooks/NoUpdates.rst deleted file mode 100644 index f58bc8f..0000000 --- a/docs/sphinx_docs/notebooks/NoUpdates.rst +++ /dev/null @@ -1,22 +0,0 @@ - -************** -No Updates -************** - -DRAFT - -1. Joy doesn't need to change. - - A. The interpreter doesn't need to change, ``viewer`` function can customize mainloop. Or use a sub-interpreter (Joy in Joy.) The base interpreter remains static. - B. Once a function has been named and defined *never change that name*. It's just not allowed. If you need to change a function ``foo`` you have to call it ``foo_II`` or something. Once a function (name mapped to behavior) is released to the public *that's it*, it's done. - C. The language evolves by adding new definitions and refactoring, always choosing new names for new functions. - -2. Following `Semantic Versioning`_ there will never be a version 2.0. - - A. `Major version must be incremented if any backwards incompatible changes are introduced to the public API. `__ - B. We never implement any backwards incompatible changes, so... - C. We could see e.g. Thun version 1.273.3! - - -.. _Semantic Versioning: https://semver.org - diff --git a/docs/sphinx_docs/notebooks/Ordered_Binary_Trees.rst b/docs/sphinx_docs/notebooks/Ordered_Binary_Trees.rst deleted file mode 100644 index 569d665..0000000 --- a/docs/sphinx_docs/notebooks/Ordered_Binary_Trees.rst +++ /dev/null @@ -1,1639 +0,0 @@ -Treating Trees I: Ordered Binary Trees -====================================== - -Although any expression in Joy can be considered to describe a -`tree `__ with the quotes -as compound nodes and the non-quote values as leaf nodes, in this page I -want to talk about `ordered binary -trees `__ and how to -make and use them. - -The basic structure, in a `crude type -notation `__, is: - -:: - - Tree :: [] | [key value Tree Tree] - -That says that a Tree is either the empty quote ``[]`` or a quote with -four items: a key, a value, and two Trees representing the left and -right branches of the tree. - -We’re going to derive some recursive functions to work with such -datastructures: - -:: - - Tree-add - Tree-delete - Tree-get - Tree-iter - Tree-iter-order - -Once these functions are defined we have a new “type” to work with, and -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.) - -.. code:: ipython2 - - from notebook_preamble import D, J, V, define, DefinitionWrapper - -Adding Nodes to the Tree ------------------------- - -Let’s consider adding nodes to a Tree structure. - -:: - - Tree value key Tree-add - ----------------------------- - Tree′ - -Adding to an empty node. -~~~~~~~~~~~~~~~~~~~~~~~~ - -If the current node is ``[]`` then you just return -``[key value [] []]``: - -:: - - Tree-add == [popop not] [[pop] dipd Tree-new] [R0] [R1] genrec - -``Tree-new`` -^^^^^^^^^^^^ - -Where ``Tree-new`` is defined as: - -:: - - value key Tree-new - ------------------------ - [key value [] []] - -Example: - -:: - - value key swap [[] []] cons cons - key value [[] []] cons cons - key [value [] []] cons - [key value [] []] - -Definition: - -:: - - Tree-new == swap [[] []] cons cons - -.. code:: ipython2 - - define('Tree-new == swap [[] []] cons cons') - -.. code:: ipython2 - - J('"v" "k" Tree-new') - - -.. parsed-literal:: - - ['k' 'v' [] []] - - -(As an implementation detail, the ``[[] []]`` literal used in the -definition of ``Tree-new`` will be reused to supply the *constant* tail -for *all* new nodes produced by it. This is one of those cases where you -get amortized storage “for free” by using `persistent -datastructures `__. -Because the tail, which is ``((), ((), ()))`` in Python, is immutable -and embedded in the definition body for ``Tree-new``, all new nodes can -reuse it as their own tail without fear that some other code somewhere -will change it.) - -Adding to a non-empty node. -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We now have to derive ``R0`` and ``R1``, consider: - -:: - - [key_n value_n left right] value key R0 [Tree-add] R1 - -In this case, there are three possibilites: the key can be greater or -less than or equal to the node’s key. In two of those cases we will need -to apply a copy of ``Tree-add``, so ``R0`` is pretty much out of the -picture. - -:: - - [R0] == [] - -A predicate to compare keys. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - [key_n value_n left right] value key [BTree-add] R1 - -The first thing we need to do is compare the the key we’re adding to the -node key and ``branch`` accordingly: - -:: - - [key_n value_n left right] value key [BTree-add] [P] [T] [E] ifte - -That would suggest something like: - -:: - - [key_n value_n left right] value key [BTree-add] P - [key_n value_n left right] value key [BTree-add] pop roll> pop first > - [key_n value_n left right] value key roll> pop first > - key [key_n value_n left right] value roll> pop first > - key key_n > - Boolean - -Let’s abstract the predicate just a little to let us specify the -comparison operator: - -:: - - P > == pop roll> pop first > - P < == pop roll> pop first < - P == pop roll> pop first - -.. code:: ipython2 - - define('P == pop roll> pop first') - -.. code:: ipython2 - - J('["old_key" 23 [] []] 17 "new_key" ["..."] P') - - -.. parsed-literal:: - - 'new_key' 'old_key' - - -If the key we’re adding is greater than the node’s key. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Here the parentheses are meant to signify that the expression is not -literal, the code in the parentheses is meant to have been evaluated: - -:: - - [key_n value_n left right] value key [Tree-add] T - ------------------------------------------------------- - [key_n value_n left (Tree-add key value right)] - -So how do we do this? We’re going to want to use ``infra`` on some -function ``K`` that has the key and value to work with, as well as the -quoted copy of ``Tree-add`` to apply somehow. Considering the node as a -stack: - -:: - - right left value_n key_n value key [Tree-add] K - ----------------------------------------------------- - right value key Tree-add left value_n key_n - -Pretty easy: - -:: - - right left value_n key_n value key [Tree-add] cons cons dipdd - right left value_n key_n [value key Tree-add] dipdd - right value key Tree-add left value_n key_n - -So: - -:: - - K == cons cons dipdd - -Looking at it from the point-of-view of the node as node again: - -:: - - [key_n value_n left right] [value key [Tree-add] K] infra - -Expand ``K`` and evaluate a little: - -:: - - [key_n value_n left right] [value key [Tree-add] K] infra - [key_n value_n left right] [value key [Tree-add] cons cons dipdd] infra - [key_n value_n left right] [[value key Tree-add] dipdd] infra - -Then, working backwards: - -:: - - [key_n value_n left right] [[value key Tree-add] dipdd] infra - [key_n value_n left right] [value key Tree-add] [dipdd] cons infra - [key_n value_n left right] value key [Tree-add] cons cons [dipdd] cons infra - -And so ``T`` is just: - -:: - - T == cons cons [dipdd] cons infra - -.. code:: ipython2 - - define('T == cons cons [dipdd] cons infra') - -.. code:: ipython2 - - J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] T') - - -.. parsed-literal:: - - ['old_k' 'old_value' 'left' 'Tree-add' 'new_key' 'new_value' 'right'] - - -If the key we’re adding is less than the node’s key. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -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 - - define('E == [P <] [Te] [Ee] ifte') - -In this case ``Te`` works that same as ``T`` but on the left child tree -instead of the right, so the only difference is that it must use -``dipd`` instead of ``dipdd``: - -:: - - Te == cons cons [dipd] cons infra - -.. code:: ipython2 - - define('Te == cons cons [dipd] cons infra') - -.. code:: ipython2 - - J('["old_k" "old_value" "left" "right"] "new_value" "new_key" ["Tree-add"] Te') - - -.. parsed-literal:: - - ['old_k' 'old_value' 'Tree-add' 'new_key' 'new_value' 'left' 'right'] - - -Else the keys must be equal. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This means we must find: - -:: - - [key old_value left right] new_value key [Tree-add] Ee - ------------------------------------------------------------ - [key new_value left right] - -This is another easy one: - -:: - - Ee == pop swap roll< rest rest cons cons - -Example: - -:: - - [key old_value left right] new_value key [Tree-add] pop swap roll< rest rest cons cons - [key old_value left right] new_value key swap roll< rest rest cons cons - [key old_value left right] key new_value roll< rest rest cons cons - key new_value [key old_value left right] rest rest cons cons - key new_value [ left right] cons cons - [key new_value left right] - -.. code:: ipython2 - - define('Ee == pop swap roll< rest rest cons cons') - -.. code:: ipython2 - - J('["k" "old_value" "left" "right"] "new_value" "k" ["Tree-add"] Ee') - - -.. parsed-literal:: - - ['k' 'new_value' 'left' 'right'] - - -Now we can define ``Tree-add`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec - -Putting it all together: - -:: - - Tree-new == swap [[] []] cons cons - P == pop roll> pop first - T == cons cons [dipdd] cons infra - Te == cons cons [dipd] cons infra - Ee == pop swap roll< rest rest cons cons - E == [P <] [Te] [Ee] ifte - R == [P >] [T] [E] ifte - - Tree-add == [popop not] [[pop] dipd Tree-new] [] [R] genrec - -.. code:: ipython2 - - define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [[P >] [T] [E] ifte] genrec') - -Examples -~~~~~~~~ - -.. code:: ipython2 - - J('[] 23 "b" Tree-add') # Initial - - -.. parsed-literal:: - - ['b' 23 [] []] - - -.. code:: ipython2 - - J('["b" 23 [] []] 88 "c" Tree-add') # Greater than - - -.. parsed-literal:: - - ['b' 23 [] ['c' 88 [] []]] - - -.. code:: ipython2 - - J('["b" 23 [] []] 88 "a" Tree-add') # Less than - - -.. parsed-literal:: - - ['b' 23 ['a' 88 [] []] []] - - -.. code:: ipython2 - - J('["b" 23 [] []] 88 "b" Tree-add') # Equal to - - -.. parsed-literal:: - - ['b' 88 [] []] - - -.. code:: ipython2 - - J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Series. - - -.. parsed-literal:: - - ['b' 23 ['a' 88 [] []] ['c' 44 [] []]] - - -.. code:: ipython2 - - J('[] [[23 "b"] [88 "a"] [44 "c"]] [i Tree-add] step') - - -.. parsed-literal:: - - ['b' 23 ['a' 88 [] []] ['c' 44 [] []]] - - -Interlude: ``cmp`` combinator ------------------------------ - -Instead of mucking about with nested ``ifte`` combinators let’s use -``cmp`` which takes two values and three quoted programs on the stack -and runs one of the three depending on the results of comparing the two -values: - -:: - - a b [G] [E] [L] cmp - ------------------------- a > b - G - - a b [G] [E] [L] cmp - ------------------------- a = b - E - - a b [G] [E] [L] cmp - ------------------------- a < b - L - -.. code:: ipython2 - - J("1 0 ['G'] ['E'] ['L'] cmp") - - -.. parsed-literal:: - - 'G' - - -.. code:: ipython2 - - J("1 1 ['G'] ['E'] ['L'] cmp") - - -.. parsed-literal:: - - 'E' - - -.. code:: ipython2 - - J("0 1 ['G'] ['E'] ['L'] cmp") - - -.. parsed-literal:: - - 'L' - - -Redefine ``Tree-add`` -~~~~~~~~~~~~~~~~~~~~~ - -We need a new non-destructive predicate ``P``: - -:: - - [node_key node_value left right] value key [Tree-add] P - ------------------------------------------------------------------------ - [node_key node_value left right] value key [Tree-add] key node_key - -Let’s start with ``over`` to get a copy of the key and then apply some -function ``Q`` with the ``nullary`` combinator so it can dig out the -node key (by throwing everything else away): - -:: - - P == over [Q] nullary - - [node_key node_value left right] value key [Tree-add] over [Q] nullary - [node_key node_value left right] value key [Tree-add] key [Q] nullary - -And ``Q`` would be: - -:: - - Q == popop popop first - - [node_key node_value left right] value key [Tree-add] key Q - [node_key node_value left right] value key [Tree-add] key popop popop first - [node_key node_value left right] value key popop first - [node_key node_value left right] first - node_key - -Or just: - -:: - - P == over [popop popop first] nullary - -.. code:: ipython2 - - define('P == over [popop popop first] nullary') - -Using ``cmp`` to simplify `our code above at -``R1`` <#Adding-to-a-non-empty-node.>`__: - -:: - - [node_key node_value left right] value key [Tree-add] R1 - [node_key node_value left right] value key [Tree-add] P [T] [E] [Te] cmp - -The line above becomes one of the three lines below: - -:: - - [node_key node_value left right] value key [Tree-add] T - [node_key node_value left right] value key [Tree-add] E - [node_key node_value left right] value key [Tree-add] Te - -The definition is a little longer but, I think, more elegant and easier -to understand: - -:: - - Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec - -.. code:: ipython2 - - define('Tree-add == [popop not] [[pop] dipd Tree-new] [] [P [T] [Ee] [Te] cmp] genrec') - -.. code:: ipython2 - - J('[] 23 "b" Tree-add 88 "a" Tree-add 44 "c" Tree-add') # Still works. - - -.. parsed-literal:: - - ['b' 23 ['a' 88 [] []] ['c' 44 [] []]] - - -A Function to Traverse this Structure -------------------------------------- - -Let’s take a crack at writing a function that can recursively iterate or -traverse these trees. - -Base case ``[]`` -~~~~~~~~~~~~~~~~ - -The stopping predicate just has to detect the empty list: - -:: - - Tree-iter == [not] [E] [R0] [R1] genrec - -And since there’s nothing at this node, we just ``pop`` it: - -:: - - Tree-iter == [not] [pop] [R0] [R1] genrec - -Node case ``[key value left right]`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now we need to figure out ``R0`` and ``R1``: - -:: - - Tree-iter == [not] [pop] [R0] [R1] genrec - == [not] [pop] [R0 [Tree-iter] R1] ifte - -Let’s look at it *in situ*: - -:: - - [key value left right] R0 [Tree-iter] R1 - -Processing the current node. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -``R0`` is almost certainly going to use ``dup`` to make a copy of the -node and then ``dip`` on some function to process the copy with it: - -:: - - [key value left right] [F] dupdip [Tree-iter] R1 - [key value left right] F [key value left right] [Tree-iter] R1 - -For example, if we’re getting all the keys ``F`` would be ``first``: - -:: - - R0 == [first] dupdip - - [key value left right] [first] dupdip [Tree-iter] R1 - [key value left right] first [key value left right] [Tree-iter] R1 - key [key value left right] [Tree-iter] R1 - -Recur -^^^^^ - -Now ``R1`` needs to apply ``[Tree-iter]`` to ``left`` and ``right``. If -we drop the key and value from the node using ``rest`` twice we are left -with an interesting situation: - -:: - - key [key value left right] [Tree-iter] R1 - key [key value left right] [Tree-iter] [rest rest] dip - key [key value left right] rest rest [Tree-iter] - key [left right] [Tree-iter] - -Hmm, will ``step`` do? - -:: - - key [left right] [Tree-iter] step - key left Tree-iter [right] [Tree-iter] step - key left-keys [right] [Tree-iter] step - key left-keys right Tree-iter - key left-keys right-keys - -Neat. So: - -:: - - R1 == [rest rest] dip step - -Putting it together -~~~~~~~~~~~~~~~~~~~ - -We have: - -:: - - Tree-iter == [not] [pop] [[F] dupdip] [[rest rest] dip step] genrec - -When I was reading this over I realized ``rest rest`` could go in -``R0``: - -:: - - Tree-iter == [not] [pop] [[F] dupdip rest rest] [step] genrec - -(And ``[step] genrec`` is such a cool and suggestive combinator!) - -Parameterizing the ``F`` per-node processing function. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - [F] Tree-iter - ------------------------------------------------------ - [not] [pop] [[F] dupdip rest rest] [step] genrec - -Working backward: - -:: - - [not] [pop] [[F] dupdip rest rest] [step] genrec - [not] [pop] [F] [dupdip rest rest] cons [step] genrec - [F] [not] [pop] roll< [dupdip rest rest] cons [step] genrec - -``Tree-iter`` -~~~~~~~~~~~~~ - -:: - - Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec - -.. code:: ipython2 - - define('Tree-iter == [not] [pop] roll< [dupdip rest rest] cons [step] genrec') - -Examples -~~~~~~~~ - -.. code:: ipython2 - - J('[] [foo] Tree-iter') # It doesn't matter what F is as it won't be used. - - -.. parsed-literal:: - - - - -.. code:: ipython2 - - J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [first] Tree-iter") - - -.. parsed-literal:: - - 'b' 'a' 'c' - - -.. code:: ipython2 - - J("['b' 23 ['a' 88 [] []] ['c' 44 [] []]] [second] Tree-iter") - - -.. parsed-literal:: - - 23 88 44 - - -Interlude: A Set-like Datastructure ------------------------------------ - -We can use this to make a set-like datastructure by just setting values -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)` `__ -time. - -.. code:: ipython2 - - J('[] [3 9 5 2 8 6 7 8 4] [0 swap Tree-add] step') - - -.. parsed-literal:: - - [3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]] - - -.. code:: ipython2 - - define('to_set == [] swap [0 swap Tree-add] step') - -.. code:: ipython2 - - J('[3 9 5 2 8 6 7 8 4] to_set') - - -.. parsed-literal:: - - [3 0 [2 0 [] []] [9 0 [5 0 [4 0 [] []] [8 0 [6 0 [] [7 0 [] []]] []]] []]] - - -And with that we can write a little program ``unique`` to remove -duplicate items from a list. - -.. code:: ipython2 - - define('unique == [to_set [first] Tree-iter] cons run') - -.. code:: ipython2 - - J('[3 9 3 5 2 9 8 8 8 6 2 7 8 4 3] unique') # Filter duplicate items. - - -.. parsed-literal:: - - [7 6 8 4 5 9 2 3] - - -A Version of ``Tree-iter`` that does In-Order Traversal -------------------------------------------------------- - -If you look back to the `non-empty case of the ``Tree-iter`` -function <#Node-case-%5Bkey-value-left-right%5D>`__ we can design a -variant that first processes the left child, then the current node, then -the right child. This will allow us to traverse the tree in sort order. - -:: - - Tree-iter-order == [not] [pop] [R0] [R1] genrec - -To define ``R0`` and ``R1`` it helps to look at them as they will appear -when they run: - -:: - - [key value left right] R0 [BTree-iter-order] R1 - -Process the left child. -~~~~~~~~~~~~~~~~~~~~~~~ - -Staring at this for a bit suggests ``dup third`` to start: - -:: - - [key value left right] R0 [Tree-iter-order] R1 - [key value left right] dup third [Tree-iter-order] R1 - [key value left right] left [Tree-iter-order] R1 - -Now maybe: - -:: - - [key value left right] left [Tree-iter-order] [cons dip] dupdip - [key value left right] left [Tree-iter-order] cons dip [Tree-iter-order] - [key value left right] [left Tree-iter-order] dip [Tree-iter-order] - left Tree-iter-order [key value left right] [Tree-iter-order] - -Process the current node. -~~~~~~~~~~~~~~~~~~~~~~~~~ - -So far, so good. Now we need to process the current node’s values: - -:: - - left Tree-iter-order [key value left right] [Tree-iter-order] [[F] dupdip] dip - left Tree-iter-order [key value left right] [F] dupdip [Tree-iter-order] - left Tree-iter-order [key value left right] F [key value left right] [Tree-iter-order] - -If ``F`` needs items from the stack below the left stuff it should have -``cons``\ ’d them before beginning maybe? For functions like ``first`` -it works fine as-is. - -:: - - left Tree-iter-order [key value left right] first [key value left right] [Tree-iter-order] - left Tree-iter-order key [key value left right] [Tree-iter-order] - -Process the right child. -~~~~~~~~~~~~~~~~~~~~~~~~ - -First ditch the rest of the node and get the right child: - -:: - - left Tree-iter-order key [key value left right] [Tree-iter-order] [rest rest rest first] dip - left Tree-iter-order key right [Tree-iter-order] - -Then, of course, we just need ``i`` to run ``Tree-iter-order`` on the -right side: - -:: - - left Tree-iter-order key right [Tree-iter-order] i - left Tree-iter-order key right Tree-iter-order - -Defining ``Tree-iter-order`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The result is a little awkward: - -:: - - R1 == [cons dip] dupdip [[F] dupdip] dip [rest rest rest first] dip i - -Let’s do a little semantic factoring: - -:: - - fourth == rest rest rest first - - proc_left == [cons dip] dupdip - proc_current == [[F] dupdip] dip - proc_right == [fourth] dip i - - Tree-iter-order == [not] [pop] [dup third] [proc_left proc_current proc_right] genrec - -Now we can sort sequences. - -.. code:: ipython2 - - #define('Tree-iter-order == [not] [pop] [dup third] [[cons dip] dupdip [[first] dupdip] dip [rest rest rest first] dip i] genrec') - - - DefinitionWrapper.add_definitions(''' - - fourth == rest rest rest first - - 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 - - ''', D) - - - - -.. code:: ipython2 - - J('[3 9 5 2 8 6 7 8 4] to_set Tree-iter-order') - - -.. parsed-literal:: - - 2 3 4 5 6 7 8 9 - - -Parameterizing the ``[F]`` function is left as an exercise for the -reader. - -Getting values by key ---------------------- - -Let’s derive a function that accepts a tree and a key and returns the -value associated with that key. - -:: - - tree key Tree-get - ----------------------- - value - -But what do we do if the key isn’t in the tree? In Python we might raise -a ``KeyError`` but I’d like to avoid exceptions in Joy if possible, and -here I think it’s possible. (Division by zero is an example of where I -think it’s probably better to let Python crash Joy. Sometimes the -machinery fails and you have to “stop the line”, I think.) - -Let’s pass the buck to the caller by making the base case a given, you -have to decide for yourself what ``[E]`` should be. - -:: - - tree key [E] Tree-get - ---------------------------- key in tree - value - - tree key [E] Tree-get - ---------------------------- key not in tree - [] key E - -The base case ``[]`` -~~~~~~~~~~~~~~~~~~~~ - -As before, the stopping predicate just has to detect the empty list: - -:: - - Tree-get == [pop not] [E] [R0] [R1] genrec - -So we define: - -:: - - Tree-get == [pop not] swap [R0] [R1] genrec - -Note that this ``Tree-get`` creates a slightly different function than -itself and *that function* does the actual recursion. This kind of -higher-level programming is unusual in most languages but natural in -Joy. - -:: - - tree key [E] [pop not] swap [R0] [R1] genrec - tree key [pop not] [E] [R0] [R1] genrec - -The anonymous specialized recursive function that will do the real work. - -:: - - [pop not] [E] [R0] [R1] genrec - -Node case ``[key value left right]`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Now we need to figure out ``R0`` and ``R1``: - -:: - - [key value left right] key R0 [BTree-get] R1 - -We want to compare the search key with the key in the node, and if they -are the same return the value, otherwise recur on one of the child -nodes. So it’s very similar to the above funtion, with ``[R0] == []`` -and ``R1 == P [T>] [E] [T<] cmp``: - -:: - - [key value left right] key [BTree-get] P [T>] [E] [T<] cmp - -Predicate -^^^^^^^^^ - -:: - - P == over [get-node-key] nullary - get-node-key == pop popop first - -The only difference is that ``get-node-key`` does one less ``pop`` -because there’s no value to discard. - -Branches -^^^^^^^^ - -Now we have to derive the branches: - -:: - - [key_n value_n left right] key [BTree-get] T> - [key_n value_n left right] key [BTree-get] E - [key_n value_n left right] key [BTree-get] T< - -Greater than and less than -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The cases of ``T>`` and ``T<`` are similar to above but instead of using -``infra`` we have to discard the rest of the structure: - -:: - - [key_n value_n left right] key [BTree-get] T> - --------------------------------------------------- - right key BTree-get - -And: - -:: - - [key_n value_n left right] key [BTree-get] T< - --------------------------------------------------- - left key BTree-get - -So: - -:: - - T> == [fourth] dipd i - T< == [third] dipd i - -E.g.: - -:: - - [key_n value_n left right] key [BTree-get] [fourth] dipd i - [key_n value_n left right] fourth key [BTree-get] i - right key [BTree-get] i - right key BTree-get - -Equal keys -^^^^^^^^^^ - -Return the node’s value: - -:: - - [key_n value_n left right] key [BTree-get] E == value_n - - E == popop second - -``Tree-get`` -~~~~~~~~~~~~ - -So: - -:: - - fourth == rest rest rest first - get-node-key == pop popop first - P == over [get-node-key] nullary - T> == [fourth] dipd i - T< == [third] dipd i - E == popop second - - Tree-get == [pop not] swap [] [P [T>] [E] [T<] cmp] genrec - -.. code:: ipython2 - - # I don't want to deal with name conflicts with the above so I'm inlining everything here. - # The original Joy system has "hide" which is a meta-command which allows you to use named - # 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 - ''') - -.. code:: ipython2 - - J('["gary" 23 [] []] "mike" [popd " not in tree" +] Tree-get') - - -.. parsed-literal:: - - 'mike not in tree' - - -.. code:: ipython2 - - J('["gary" 23 [] []] "gary" [popop "err"] Tree-get') - - -.. parsed-literal:: - - 23 - - -.. code:: ipython2 - - J(''' - - [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step - - 'c' [popop 'not found'] Tree-get - - ''') - - -.. parsed-literal:: - - 2 - - -.. code:: ipython2 - - J(''' - - [] [[0 'a'] [1 'b'] [2 'c']] [i Tree-add] step - - 'd' [popop 'not found'] Tree-get - - ''') - - -.. parsed-literal:: - - 'not found' - - -Tree-delete ------------ - -Now let’s write a function that can return a tree datastructure with a -key, value pair deleted: - -:: - - tree key Tree-delete - --------------------------- - tree - -If the key is not in tree it just returns the tree unchanged. - -Base case -~~~~~~~~~ - -Same as above. - -:: - - Tree-Delete == [pop not] [pop] [R0] [R1] genrec - -Recur -~~~~~ - -Now we get to figure out the recursive case. We need the node’s key to -compare and we need to carry the key into recursive branches. Let ``D`` -be shorthand for ``Tree-Delete``: - -:: - - D == Tree-Delete == [pop not] [pop] [R0] [R1] genrec - - [node_key node_value left right] key R0 [D] R1 - [node_key node_value left right] key over first swap dup [D] cons R1′ - [node_key node_value left right] key [...] first swap dup [D] cons R1′ - [node_key node_value left right] key node_key swap dup [D] cons R1′ - [node_key node_value left right] node_key key dup [D] cons R1′ - [node_key node_value left right] node_key key key [D] cons R1′ - [node_key node_value left right] node_key key [key D] R1′ - -And then: - -:: - - [node_key node_value left right] node_key key [key D] R1′ - [node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp - [node_key node_value left right] node_key key [key D] roll> [T>] [E] [T<] cmp - [node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp - -So: - -:: - - R0 == over first swap dup - R1 == cons roll> [T>] [E] [T<] cmp - -Compare Keys -~~~~~~~~~~~~ - -The last line above: - -:: - - [node_key node_value left right] [key D] node_key key [T>] [E] [T<] cmp - -Then becomes one of these three: - -:: - - [node_key node_value left right] [key D] T> - [node_key node_value left right] [key D] E - [node_key node_value left right] [key D] T< - -Greater than case and less than case -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - [node_key node_value left right] [F] T> - ------------------------------------------------- - [node_key node_value (left F) right] - - - [node_key node_value left right] [F] T< - ------------------------------------------------- - [node_key node_value left (right F)] - -First, treating the node as a stack: - -:: - - right left node_value node_key [key D] dipd - right left key D node_value node_key - right left' node_value node_key - -Ergo: - -:: - - [node_key node_value left right] [key D] [dipd] cons infra - -So: - -:: - - T> == [dipd] cons infra - T< == [dipdd] cons infra - -The else case -~~~~~~~~~~~~~ - -We have found the node in the tree where ``key`` equals ``node_key``. We -need to replace the current node with something - -:: - - [node_key node_value left right] [key D] E - ------------------------------------------------ - tree - -We have to handle three cases, so let’s use ``cond``. - -One or more child nodes are ``[]`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The first two cases are symmetrical: if we only have one non-empty child -node return it. If both child nodes are empty return an empty node. - -:: - - E == [ - [[pop third not] pop fourth] - [[pop fourth not] pop third] - [default] - ] cond - -Both child nodes are non-empty. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If both child nodes are non-empty, we find the highest node in our lower -sub-tree, take its key and value to replace (delete) our own, then get -rid of it by recursively calling delete() on our lower sub-node with our -new key. - -(We could also find the lowest node in our higher sub-tree and take its -key and value and delete it. I only implemented one of these two -symmetrical options. Over a lot of deletions this might make the tree -more unbalanced. Oh well.) - -The initial structure of the default function: - -:: - - default == [E′] cons infra - - [node_key node_value left right] [key D] default - [node_key node_value left right] [key D] [E′] cons infra - [node_key node_value left right] [[key D] E′] infra - - right left node_value node_key [key D] E′ - -First things first, we no longer need this node’s key and value: - -:: - - right left node_value node_key [key D] roll> popop E″ - right left [key D] node_value node_key popop E″ - right left [key D] E″ - -We have to we find the highest (right-most) node in our lower (left) sub-tree: -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -:: - - right left [key D] E″ - -Ditch the key: - -:: - - right left [key D] rest E‴ - right left [D] E‴ - -Find the right-most node: - -:: - - right left [D] [dup W] dip E⁗ - right left dup W [D] E⁗ - right left left W [D] E⁗ - -Consider: - -:: - - left W - -We know left is not empty: - -:: - - [L_key L_value L_left L_right] W - -We want to keep extracting the right node as long as it is not empty: - -:: - - W.rightmost == [P] [B] while - - left W.rightmost W′ - -The predicate: - -:: - - [L_key L_value L_left L_right] P - [L_key L_value L_left L_right] fourth - L_right - -This can run on ``[]`` so must be guarded: - -:: - - ?fourth == [] [fourth] [] ifte - -( if_not_empty == [] swap [] ifte ?fourth == [fourth] if_not_empty ) - -The body is just ``fourth``: - -:: - - left [?fourth] [fourth] while W′ - rightest W′ - -So: - -:: - - W.rightmost == [?fourth] [fourth] while - -Found right-most node in our left sub-tree -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -We know rightest is not empty: - -:: - - [R_key R_value R_left R_right] W′ - [R_key R_value R_left R_right] W′ - [R_key R_value R_left R_right] uncons uncons pop - R_key [R_value R_left R_right] uncons pop - R_key R_value [R_left R_right] pop - R_key R_value - -So: - -:: - - W == [?fourth] [fourth] while uncons uncons pop - -And: - -:: - - right left left W [D] E⁗ - right left R_key R_value [D] E⁗ - -Replace current node key and value, recursively delete rightmost -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Final stretch. We want to end up with something like: - -:: - - right left [R_key D] i R_value R_key - right left R_key D R_value R_key - right left′ R_value R_key - -If we adjust our definition of ``W`` to include ``over`` at the end: - -:: - - W == [fourth] [fourth] while uncons uncons pop over - -That will give us: - -:: - - right left R_key R_value R_key [D] E⁗ - - right left R_key R_value R_key [D] cons dipd E⁗′ - right left R_key R_value [R_key D] dipd E⁗′ - right left R_key D R_key R_value E⁗′ - right left′ R_key R_value E⁗′ - right left′ R_key R_value swap - right left′ R_value R_key - -So: - -:: - - E′ == roll> popop E″ - - E″ == rest E‴ - - E‴ == [dup W] dip E⁗ - - E⁗ == cons dipdd swap - -Substituting: - -:: - - W == [fourth] [fourth] while uncons uncons pop over - E′ == roll> popop rest [dup W] dip cons dipd swap - E == [ - [[pop third not] pop fourth] - [[pop fourth not] pop third] - [[E′] cons infra] - ] cond - -Minor rearrangement, move ``dup`` into ``W``: - -:: - - W == dup [fourth] [fourth] while uncons uncons pop over - E′ == roll> popop rest [W] dip cons dipd swap - E == [ - [[pop third not] pop fourth] - [[pop fourth not] pop third] - [[E′] cons infra] - ] cond - -Refactoring -~~~~~~~~~~~ - -:: - - W.rightmost == [fourth] [fourth] while - W.unpack == uncons uncons pop - W == dup W.rightmost W.unpack over - E.clear_stuff == roll> popop rest - E.delete == cons dipd - 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 - BTree-Delete == [pop not] swap [R0] [R1] genrec - -By the standards of the code I’ve written so far, this is a *huge* Joy -program. - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'c' Tree-Delete ") - - -.. parsed-literal:: - - ['a' 23 [] ['b' 88 [] []]] - - -.. code:: ipython2 - - J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'b' Tree-Delete ") - - -.. parsed-literal:: - - ['a' 23 [] ['c' 44 [] []]] - - -.. code:: ipython2 - - J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'a' Tree-Delete ") - - -.. parsed-literal:: - - ['b' 88 [] ['c' 44 [] []]] - - -.. code:: ipython2 - - J("['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] 'der' Tree-Delete ") - - -.. parsed-literal:: - - ['a' 23 [] ['b' 88 [] ['c' 44 [] []]]] - - -.. code:: ipython2 - - J('[] [4 2 3 1 6 7 5 ] [0 swap Tree-add] step') - - -.. parsed-literal:: - - [4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] - - -.. code:: ipython2 - - J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 3 Tree-Delete ") - - -.. parsed-literal:: - - [4 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]] - - -.. code:: ipython2 - - J("[4 0 [2 0 [1 0 [] []] [3 0 [] []]] [6 0 [5 0 [] []] [7 0 [] []]]] 4 Tree-Delete ") - - -.. parsed-literal:: - - [3 0 [2 0 [1 0 [] []] []] [6 0 [5 0 [] []] [7 0 [] []]]] - - -Appendix: The source code. --------------------------- - -:: - - fourth == rest_two rest first - ?fourth == [] [fourth] [] ifte - first_two == uncons uncons pop - ccons == cons cons - cinf == cons infra - rest_two == rest rest - - _Tree_T> == [dipd] cinf - _Tree_T< == [dipdd] cinf - - _Tree_add_P == over [popop popop first] nullary - _Tree_add_T> == ccons _Tree_T< - _Tree_add_T< == ccons _Tree_T> - _Tree_add_Ee == pop swap roll< rest_two ccons - _Tree_add_R == _Tree_add_P [_Tree_add_T>] [_Tree_add_Ee] [_Tree_add_T<] cmp - _Tree_add_E == [pop] dipd Tree-new - - _Tree_iter_order_left == [cons dip] dupdip - _Tree_iter_order_current == [[F] dupdip] dip - _Tree_iter_order_right == [fourth] dip i - _Tree_iter_order_R == _Tree_iter_order_left _Tree_iter_order_current _Tree_iter_order_right - - _Tree_get_P == over [pop popop first] nullary - _Tree_get_T> == [fourth] dipd i - _Tree_get_T< == [third] dipd i - _Tree_get_E == popop second - _Tree_get_R == _Tree_get_P [_Tree_get_T>] [_Tree_get_E] [_Tree_get_T<] cmp - - _Tree_delete_rightmost == [?fourth] [fourth] while - _Tree_delete_clear_stuff == roll> popop rest - _Tree_delete_del == dip cons dipd swap - _Tree_delete_W == dup _Tree_delete_rightmost first_two over - _Tree_delete_E.0 == _Tree_delete_clear_stuff [_Tree_delete_W] _Tree_delete_del - _Tree_delete_E == [[[pop third not] pop fourth] [[pop fourth not] pop third] [[_Tree_delete_E.0] cinf]] cond - _Tree_delete_R0 == over first swap dup - _Tree_delete_R1 == cons roll> [_Tree_T>] [_Tree_delete_E] [_Tree_T<] cmp - - Tree-new == swap [[] []] ccons - Tree-add == [popop not] [_Tree_add_E] [] [_Tree_add_R] genrec - Tree-iter == [not] [pop] roll< [dupdip rest_two] cons [step] genrec - Tree-iter-order == [not] [pop] [dup third] [_Tree_iter_order_R] genrec - Tree-get == [pop not] swap [] [_Tree_get_R] genrec - Tree-delete == [pop not] [pop] [_Tree_delete_R0] [_Tree_delete_R1] genrec diff --git a/docs/sphinx_docs/notebooks/Quadratic.rst b/docs/sphinx_docs/notebooks/Quadratic.rst deleted file mode 100644 index 3262e84..0000000 --- a/docs/sphinx_docs/notebooks/Quadratic.rst +++ /dev/null @@ -1,158 +0,0 @@ -.. code:: ipython2 - - from notebook_preamble import J, V, define - -`Quadratic formula `__ -======================================================================= - -Cf. -`jp-quadratic.html `__ - -:: - - -b ± sqrt(b^2 - 4 * a * c) - -------------------------------- - 2 * a - -:math:`\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}` - -Write a straightforward program with variable names. ----------------------------------------------------- - -This math translates to Joy code in a straightforward manner. We are -going to use named variables to keep track of the arguments, then write -a definition without them. - -``-b`` -~~~~~~ - -:: - - b neg - -``sqrt(b^2 - 4 * a * c)`` -~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - b sqr 4 a c * * - sqrt - -``/2a`` -~~~~~~~ - -:: - - a 2 * / - -``±`` -~~~~~ - -There is a function ``pm`` that accepts two values on the stack and -replaces them with their sum and difference. - -:: - - pm == [+] [-] cleave popdd - -Putting Them Together -~~~~~~~~~~~~~~~~~~~~~ - -:: - - b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2 - -We use ``app2`` to compute both roots by using a quoted program -``[2a /]`` built with ``cons``. - -Derive a definition. --------------------- - -Working backwards we use ``dip`` and ``dipd`` to extract the code from -the variables: - -:: - - b neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2 - b [neg] dupdip sqr 4 a c * * - sqrt pm a 2 * [/] cons app2 - b a c [[neg] dupdip sqr 4] dipd * * - sqrt pm a 2 * [/] cons app2 - b a c a [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 - b a c over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 - -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 - - define('quadratic == over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2') - -Let’s try it out: - -.. code:: ipython2 - - J('3 1 1 quadratic') - - -.. parsed-literal:: - - -0.3819660112501051 -2.618033988749895 - - -If you look at the Joy evaluation trace you can see that the first few -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 - - V('-5 1 4 quadratic') - - -.. parsed-literal:: - - . -5 1 4 quadratic - -5 . 1 4 quadratic - -5 1 . 4 quadratic - -5 1 4 . quadratic - -5 1 4 . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 - -5 1 4 1 . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2 - -5 1 4 1 [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2 - -5 1 4 . [[neg] dupdip sqr 4] dipd * * - sqrt pm 1 2 * [/] cons app2 - -5 1 4 [[neg] dupdip sqr 4] . dipd * * - sqrt pm 1 2 * [/] cons app2 - -5 . [neg] dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - -5 [neg] . dupdip sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - -5 . neg -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 . -5 sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 -5 . sqr 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 -5 . dup mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 -5 -5 . mul 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 25 . 4 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 25 4 . 1 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 25 4 1 . 4 * * - sqrt pm 1 2 * [/] cons app2 - 5 25 4 1 4 . * * - sqrt pm 1 2 * [/] cons app2 - 5 25 4 4 . * - sqrt pm 1 2 * [/] cons app2 - 5 25 16 . - sqrt pm 1 2 * [/] cons app2 - 5 9 . sqrt pm 1 2 * [/] cons app2 - 5 3.0 . pm 1 2 * [/] cons app2 - 8.0 2.0 . 1 2 * [/] cons app2 - 8.0 2.0 1 . 2 * [/] cons app2 - 8.0 2.0 1 2 . * [/] cons app2 - 8.0 2.0 2 . [/] cons app2 - 8.0 2.0 2 [/] . cons app2 - 8.0 2.0 [2 /] . app2 - [8.0] [2 /] . infra first [2.0] [2 /] infra first - 8.0 . 2 / [] swaack first [2.0] [2 /] infra first - 8.0 2 . / [] swaack first [2.0] [2 /] infra first - 4.0 . [] swaack first [2.0] [2 /] infra first - 4.0 [] . swaack first [2.0] [2 /] infra first - [4.0] . first [2.0] [2 /] infra first - 4.0 . [2.0] [2 /] infra first - 4.0 [2.0] . [2 /] infra first - 4.0 [2.0] [2 /] . infra first - 2.0 . 2 / [4.0] swaack first - 2.0 2 . / [4.0] swaack first - 1.0 . [4.0] swaack first - 1.0 [4.0] . swaack first - 4.0 [1.0] . first - 4.0 1.0 . - - diff --git a/docs/sphinx_docs/notebooks/Recursion_Combinators.rst b/docs/sphinx_docs/notebooks/Recursion_Combinators.rst deleted file mode 100644 index 9159882..0000000 --- a/docs/sphinx_docs/notebooks/Recursion_Combinators.rst +++ /dev/null @@ -1,690 +0,0 @@ -.. code:: ipython2 - - from notebook_preamble import D, DefinitionWrapper, J, V, define - -Recursion Combinators -===================== - -This article describes the ``genrec`` combinator, how to use it, and -several generic specializations. - -:: - - [if] [then] [rec1] [rec2] genrec - --------------------------------------------------------------------- - [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte - -From “Recursion Theory and Joy” (j05cmp.html) by Manfred von Thun: - - “The genrec combinator takes four program parameters in addition to - whatever data parameters it needs. Fourth from the top is an if-part, - followed by a then-part. If the if-part yields true, then the - then-part is executed and the combinator terminates. The other two - parameters are the rec1-part and the rec2-part. If the if-part yields - false, the rec1-part is executed. Following that the four program - parameters and the combinator are again pushed onto the stack bundled - up in a quoted form. Then the rec2-part is executed, where it will - find the bundled form. Typically it will then execute the bundled - form, either with i or with app2, or some other combinator.” - -Designing Recursive Functions ------------------------------ - -The way to design one of these is to fix your base case and test and -then treat ``R1`` and ``R2`` as an else-part “sandwiching” a quotation -of the whole function. - -For example, given a (general recursive) function ``F``: - -:: - - F == [I] [T] [R1] [R2] genrec - == [I] [T] [R1 [F] R2] ifte - -If the ``[I]`` predicate is false you must derive ``R1`` and ``R2`` -from: - -:: - - ... R1 [F] R2 - -Set the stack arguments in front and figure out what ``R1`` and ``R2`` -have to do to apply the quoted ``[F]`` in the proper way. - -Primitive Recursive Functions ------------------------------ - -Primitive recursive functions are those where ``R2 == i``. - -:: - - P == [I] [T] [R] primrec - == [I] [T] [R [P] i] ifte - == [I] [T] [R P] ifte - -`Hylomorphism `__ ------------------------------------------------------------------------------------- - -A -`hylomorphism `__ -is a recursive function ``H :: A -> C`` that converts a value of type -``A`` into a value of type ``C`` by means of: - -- A generator ``G :: A -> (B, A)`` -- A combiner ``F :: (B, C) -> C`` -- A predicate ``P :: A -> Bool`` to detect the base case -- A base case value ``c :: C`` -- Recursive calls (zero or more); it has a “call stack in the form of a - cons list”. - -It may be helpful to see this function implemented in imperative Python -code. - -.. code:: ipython2 - - 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 - - return H - -Cf. `“Bananas, Lenses, & Barbed -Wire” `__ - -Note that during evaluation of ``H()`` the intermediate ``b`` values are -stored in the Python call stack. This is what is meant by “call stack in -the form of a cons list”. - -Hylomorphism in Joy -------------------- - -We can define a combinator ``hylomorphism`` that will make a -hylomorphism combinator ``H`` from constituent parts. - -:: - - H == [P] c [G] [F] hylomorphism - -The function ``H`` is recursive, so we start with ``ifte`` and set the -else-part to some function ``J`` that will contain a quoted copy of -``H``. (The then-part just discards the leftover ``a`` and replaces it -with the base case value ``c``.) - -:: - - H == [P] [pop c] [J] ifte - -The else-part ``J`` gets just the argument ``a`` on the stack. - -:: - - a J - a G The first thing to do is use the generator G - aa b which produces b and a new aa - aa b [H] dip we recur with H on the new aa - aa H b F and run F on the result. - -This gives us a definition for ``J``. - -:: - - J == G [H] dip F - -Plug it in and convert to genrec. - -:: - - H == [P] [pop c] [G [H] dip F] ifte - H == [P] [pop c] [G] [dip F] genrec - -This is the form of a hylomorphism in Joy, which nicely illustrates that -it is a simple specialization of the general recursion combinator. - -:: - - H == [P] c [G] [F] hylomorphism == [P] [pop c] [G] [dip F] genrec - -Derivation of ``hylomorphism`` combinator ------------------------------------------ - -Now we just need to derive a definition that builds the ``genrec`` -arguments out of the pieces given to the ``hylomorphism`` combinator. - -:: - - [P] c [G] [F] hylomorphism - ------------------------------------------ - [P] [pop c] [G] [dip F] genrec - -Working in reverse: - -- Use ``swoncat`` twice to decouple ``[c]`` and ``[F]``. -- Use ``unit`` to dequote ``c``. -- Use ``dipd`` to untangle ``[unit [pop] swoncat]`` from the givens. - -So: - -:: - - H == [P] [pop c] [G] [dip F] genrec - [P] [c] [pop] swoncat [G] [F] [dip] swoncat genrec - [P] c unit [pop] swoncat [G] [F] [dip] swoncat genrec - [P] c [G] [F] [unit [pop] swoncat] dipd [dip] swoncat genrec - -At this point all of the arguments (givens) to the hylomorphism are to -the left so we have a definition for ``hylomorphism``: - -:: - - hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec - -.. code:: ipython2 - - define('hylomorphism == [unit [pop] swoncat] dipd [dip] swoncat genrec') - -Example: Finding `Triangular Numbers `__ -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Let’s write a function that, given a positive integer, returns the sum -of all positive integers less than that one. (In this case the types -``A``, ``B`` and ``C`` are all ``int``.) - -To sum a range of integers from 0 to *n* - 1: - -- ``[P]`` is ``[1 <=]`` -- ``c`` is ``0`` -- ``[G]`` is ``[-- dup]`` -- ``[F]`` is ``[+]`` - -.. code:: ipython2 - - define('triangular_number == [1 <=] 0 [-- dup] [+] hylomorphism') - -Let’s try it: - -.. code:: ipython2 - - J('5 triangular_number') - - -.. parsed-literal:: - - 10 - - -.. code:: ipython2 - - J('[0 1 2 3 4 5 6] [triangular_number] map') - - -.. parsed-literal:: - - [0 0 1 3 6 10 15] - - -Four Specializations --------------------- - -There are at least four kinds of recursive combinator, depending on two -choices. The first choice is whether the combiner function ``F`` should -be evaluated during the recursion or pushed into the pending expression -to be “collapsed” at the end. The second choice is whether the combiner -needs to operate on the current value of the datastructure or the -generator’s output, in other words, whether ``F`` or ``G`` should run -first in the recursive branch. - -:: - - H1 == [P] [pop c] [G ] [dip F] genrec - H2 == c swap [P] [pop] [G [F] dip ] [i] genrec - H3 == [P] [pop c] [ [G] dupdip ] [dip F] genrec - H4 == c swap [P] [pop] [ [F] dupdip G] [i] genrec - -The working of the generator function ``G`` differs slightly for each. -Consider the recursive branches: - -:: - - ... a G [H1] dip F w/ a G == a′ b - - ... c a G [F] dip H2 a G == b a′ - - ... a [G] dupdip [H3] dip F a G == a′ - - ... c a [F] dupdip G H4 a G == a′ - -The following four sections illustrate how these work, omitting the -predicate evaluation. - -``H1`` -~~~~~~ - -:: - - H1 == [P] [pop c] [G] [dip F] genrec - -Iterate n times. - -:: - - ... a G [H1] dip F - ... a′ b [H1] dip F - ... a′ H1 b F - ... a′ G [H1] dip F b F - ... a″ b′ [H1] dip F b F - ... a″ H1 b′ F b F - ... a″ G [H1] dip F b′ F b F - ... a‴ b″ [H1] dip F b′ F b F - ... a‴ H1 b″ F b′ F b F - ... a‴ pop c b″ F b′ F b F - ... c b″ F b′ F b F - ... d b′ F b F - ... d′ b F - ... d″ - -This form builds up a pending expression (continuation) that contains -the intermediate results along with the pending combiner functions. When -the base case is reached the last term is replaced by the identity value -``c`` and the continuation “collapses” into the final result using the -combiner ``F``. - -``H2`` -~~~~~~ - -When you can start with the identity value ``c`` on the stack and the -combiner ``F`` can operate as you go using the intermediate results -immediately rather than queuing them up, use this form. An important -difference is that the generator function must return its results in the -reverse order. - -:: - - H2 == c swap [P] [pop] [G [F] dip] primrec - - ... c a G [F] dip H2 - ... c b a′ [F] dip H2 - ... c b F a′ H2 - ... d a′ H2 - ... d a′ G [F] dip H2 - ... d b′ a″ [F] dip H2 - ... d b′ F a″ H2 - ... d′ a″ H2 - ... d′ a″ G [F] dip H2 - ... d′ b″ a‴ [F] dip H2 - ... d′ b″ F a‴ H2 - ... d″ a‴ H2 - ... d″ a‴ pop - ... d″ - -``H3`` -~~~~~~ - -If you examine the traces above you’ll see that the combiner ``F`` only -gets to operate on the results of ``G``, it never “sees” the first value -``a``. If the combiner and the generator both need to work on the -current value then ``dup`` must be used, and the generator must produce -one item instead of two (the b is instead the duplicate of a.) - -:: - - H3 == [P] [pop c] [[G] dupdip] [dip F] genrec - - ... a [G] dupdip [H3] dip F - ... a G a [H3] dip F - ... a′ a [H3] dip F - ... a′ H3 a F - ... a′ [G] dupdip [H3] dip F a F - ... a′ G a′ [H3] dip F a F - ... a″ a′ [H3] dip F a F - ... a″ H3 a′ F a F - ... a″ [G] dupdip [H3] dip F a′ F a F - ... a″ G a″ [H3] dip F a′ F a F - ... a‴ a″ [H3] dip F a′ F a F - ... a‴ H3 a″ F a′ F a F - ... a‴ pop c a″ F a′ F a F - ... c a″ F a′ F a F - ... d a′ F a F - ... d′ a F - ... d″ - -``H4`` -~~~~~~ - -And, last but not least, if you can combine as you go, starting with -``c``, and the combiner ``F`` needs to work on the current item, this is -the form: - -:: - - H4 == c swap [P] [pop] [[F] dupdip G] primrec - - ... c a [F] dupdip G H4 - ... c a F a G H4 - ... d a G H4 - ... d a′ H4 - ... d a′ [F] dupdip G H4 - ... d a′ F a′ G H4 - ... d′ a′ G H4 - ... d′ a″ H4 - ... d′ a″ [F] dupdip G H4 - ... d′ a″ F a″ G H4 - ... d″ a″ G H4 - ... d″ a‴ H4 - ... d″ a‴ pop - ... d″ - -Anamorphism ------------ - -An anamorphism can be defined as a hylomorphism that uses ``[]`` for -``c`` and ``swons`` for ``F``. An anamorphic function builds a list of -values. - -:: - - A == [P] [] [G] [swons] hylomorphism - -``range`` et. al. An example of an anamorphism is the ``range`` function which generates the list of integers from 0 to *n* - 1 given *n*. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Each of the above variations can be used to make four slightly different -``range`` functions. - -``range`` with ``H1`` -^^^^^^^^^^^^^^^^^^^^^ - -:: - - H1 == [P] [pop c] [G] [dip F] genrec - == [0 <=] [pop []] [-- dup] [dip swons] genrec - -.. code:: ipython2 - - define('range == [0 <=] [] [-- dup] [swons] hylomorphism') - -.. code:: ipython2 - - J('5 range') - - -.. parsed-literal:: - - [4 3 2 1 0] - - -``range`` with ``H2`` -^^^^^^^^^^^^^^^^^^^^^ - -:: - - H2 == c swap [P] [pop] [G [F] dip] primrec - == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec - -.. code:: ipython2 - - define('range_reverse == [] swap [0 <=] [pop] [-- dup [swons] dip] primrec') - -.. code:: ipython2 - - J('5 range_reverse') - - -.. parsed-literal:: - - [0 1 2 3 4] - - -``range`` with ``H3`` -^^^^^^^^^^^^^^^^^^^^^ - -:: - - H3 == [P] [pop c] [[G] dupdip] [dip F] genrec - == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec - -.. code:: ipython2 - - define('ranger == [0 <=] [pop []] [[--] dupdip] [dip swons] genrec') - -.. code:: ipython2 - - J('5 ranger') - - -.. parsed-literal:: - - [5 4 3 2 1] - - -``range`` with ``H4`` -^^^^^^^^^^^^^^^^^^^^^ - -:: - - H4 == c swap [P] [pop] [[F] dupdip G ] primrec - == [] swap [0 <=] [pop] [[swons] dupdip --] primrec - -.. code:: ipython2 - - define('ranger_reverse == [] swap [0 <=] [pop] [[swons] dupdip --] primrec') - -.. code:: ipython2 - - J('5 ranger_reverse') - - -.. parsed-literal:: - - [1 2 3 4 5] - - -Hopefully this illustrates the workings of the variations. For more -insight you can run the cells using the ``V()`` function instead of the -``J()`` function to get a trace of the Joy evaluation. - -Catamorphism ------------- - -A catamorphism can be defined as a hylomorphism that uses -``[uncons swap]`` for ``[G]`` and ``[[] =]`` (or just ``[not]``) for the -predicate ``[P]``. A catamorphic function tears down a list term-by-term -and makes some new value. - -:: - - C == [not] c [uncons swap] [F] hylomorphism - -.. code:: ipython2 - - define('swuncons == uncons swap') # Awkward name. - -An example of a catamorphism is the sum function. - -:: - - sum == [not] 0 [swuncons] [+] hylomorphism - -.. code:: ipython2 - - define('sum == [not] 0 [swuncons] [+] hylomorphism') - -.. code:: ipython2 - - J('[5 4 3 2 1] sum') - - -.. parsed-literal:: - - 15 - - -The ``step`` combinator -~~~~~~~~~~~~~~~~~~~~~~~ - -The ``step`` combinator will usually be better to use than -``catamorphism``. - -.. code:: ipython2 - - J('[step] help') - - -.. parsed-literal:: - - Run a quoted program on each item in a sequence. - :: - - ... [] [Q] . step - ----------------------- - ... . - - - ... [a] [Q] . step - ------------------------ - ... a . Q - - - ... [a b c] [Q] . step - ---------------------------------------- - ... a . Q [b c] [Q] step - - The step combinator executes the quotation on each member of the list - on top of the stack. - - - -.. code:: ipython2 - - define('sum == 0 swap [+] step') - -.. code:: ipython2 - - J('[5 4 3 2 1] sum') - - -.. parsed-literal:: - - 15 - - -Example: Factorial Function ---------------------------- - -For the Factorial function: - -:: - - H4 == c swap [P] [pop] [[F] dupdip G] primrec - -With: - -:: - - c == 1 - F == * - G == -- - P == 1 <= - -.. code:: ipython2 - - define('factorial == 1 swap [1 <=] [pop] [[*] dupdip --] primrec') - -.. code:: ipython2 - - J('5 factorial') - - -.. parsed-literal:: - - 120 - - -Example: ``tails`` ------------------- - -An example of a paramorphism for lists given in the `“Bananas…” -paper `__ -is ``tails`` which returns the list of “tails” of a list. - -:: - - [1 2 3] tails - -------------------- - [[] [3] [2 3]] - -We can build as we go, and we want ``F`` to run after ``G``, so we use -pattern ``H2``: - -:: - - H2 == c swap [P] [pop] [G [F] dip] primrec - -We would use: - -:: - - c == [] - F == swons - G == rest dup - P == not - -.. code:: ipython2 - - define('tails == [] swap [not] [pop] [rest dup [swons] dip] primrec') - -.. code:: ipython2 - - J('[1 2 3] tails') - - -.. parsed-literal:: - - [[] [3] [2 3]] - - -Conclusion: Patterns of Recursion ---------------------------------- - -Our story so far… - -Hylo-, Ana-, Cata- -~~~~~~~~~~~~~~~~~~ - -:: - - H == [P ] [pop c ] [G ] [dip F ] genrec - A == [P ] [pop []] [G ] [dip swap cons] genrec - C == [not] [pop c ] [uncons swap] [dip F ] genrec - -Para-, ?-, ?- -~~~~~~~~~~~~~ - -:: - - P == c swap [P ] [pop] [[F ] dupdip G ] primrec - ? == [] swap [P ] [pop] [[swap cons] dupdip G ] primrec - ? == c swap [not] [pop] [[F ] dupdip uncons swap] primrec - -Appendix: Fun with Symbols --------------------------- - -:: - - |[ (c, F), (G, P) ]| == (|c, F|) • [(G, P)] - -`“Bananas, Lenses, & Barbed -Wire” `__ - -:: - - (|...|) [(...)] [<...>] - -I think they are having slightly too much fun with the symbols. However, -“Too much is always better than not enough.” diff --git a/docs/sphinx_docs/notebooks/Replacing.rst b/docs/sphinx_docs/notebooks/Replacing.rst deleted file mode 100644 index 0f90445..0000000 --- a/docs/sphinx_docs/notebooks/Replacing.rst +++ /dev/null @@ -1,147 +0,0 @@ -Replacing Functions in the Dictionary -===================================== - -For now, there is no way to define new functions from within the Joy -language. All functions (and the interpreter) all accept and return a -dictionary parameter (in addition to the stack and expression) so that -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. - -.. code:: ipython2 - - from notebook_preamble import D, J, V - -A long trace ------------- - -.. code:: ipython2 - - V('[23 18] average') - - -.. parsed-literal:: - - . [23 18] average - [23 18] . average - [23 18] . [sum 1.0 *] [size] cleave / - [23 18] [sum 1.0 *] . [size] cleave / - [23 18] [sum 1.0 *] [size] . cleave / - [23 18] [sum 1.0 *] [size] . [i] app2 [popd] dip / - [23 18] [sum 1.0 *] [size] [i] . app2 [popd] dip / - [23 18] [[sum 1.0 *] [23 18]] [i] . infra first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] [sum 1.0 *] . i [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] . sum 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41 . 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41 1.0 . * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41.0 . [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41.0 [[23 18]] . swaack first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] [41.0] . first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] 41.0 . [[size] [23 18]] [i] infra first [popd] dip / - [23 18] 41.0 [[size] [23 18]] . [i] infra first [popd] dip / - [23 18] 41.0 [[size] [23 18]] [i] . infra first [popd] dip / - [23 18] [size] . i [41.0 [23 18]] swaack first [popd] dip / - [23 18] . size [41.0 [23 18]] swaack first [popd] dip / - [23 18] . 0 swap [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - [23 18] 0 . swap [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 0 [23 18] . [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 0 [23 18] [pop ++] . step [41.0 [23 18]] swaack first [popd] dip / - 0 23 [pop ++] . i [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 0 23 . pop ++ [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 0 . ++ [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 1 . [18] [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 1 [18] . [pop ++] step [41.0 [23 18]] swaack first [popd] dip / - 1 [18] [pop ++] . step [41.0 [23 18]] swaack first [popd] dip / - 1 18 [pop ++] . i [41.0 [23 18]] swaack first [popd] dip / - 1 18 . pop ++ [41.0 [23 18]] swaack first [popd] dip / - 1 . ++ [41.0 [23 18]] swaack first [popd] dip / - 2 . [41.0 [23 18]] swaack first [popd] dip / - 2 [41.0 [23 18]] . swaack first [popd] dip / - [23 18] 41.0 [2] . first [popd] dip / - [23 18] 41.0 2 . [popd] dip / - [23 18] 41.0 2 [popd] . dip / - [23 18] 41.0 . popd 2 / - 41.0 . 2 / - 41.0 2 . / - 20.5 . - - -Replacing ``size`` with a Python version ----------------------------------------- - -Both ``sum`` and ``size`` each convert a sequence to a single value. - -:: - - sum == 0 swap [+] step - size == 0 swap [pop ++] step - -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 - - 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 - -Now we replace the old version in the dictionary with the new version, -and re-evaluate the expression. - -.. code:: ipython2 - - D['size'] = size - -A shorter trace ---------------- - -You can see that ``size`` now executes in a single step. - -.. code:: ipython2 - - V('[23 18] average') - - -.. parsed-literal:: - - . [23 18] average - [23 18] . average - [23 18] . [sum 1.0 *] [size] cleave / - [23 18] [sum 1.0 *] . [size] cleave / - [23 18] [sum 1.0 *] [size] . cleave / - [23 18] [sum 1.0 *] [size] . [i] app2 [popd] dip / - [23 18] [sum 1.0 *] [size] [i] . app2 [popd] dip / - [23 18] [[sum 1.0 *] [23 18]] [i] . infra first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] [sum 1.0 *] . i [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] . sum 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41 . 1.0 * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41 1.0 . * [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41.0 . [[23 18]] swaack first [[size] [23 18]] [i] infra first [popd] dip / - 41.0 [[23 18]] . swaack first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] [41.0] . first [[size] [23 18]] [i] infra first [popd] dip / - [23 18] 41.0 . [[size] [23 18]] [i] infra first [popd] dip / - [23 18] 41.0 [[size] [23 18]] . [i] infra first [popd] dip / - [23 18] 41.0 [[size] [23 18]] [i] . infra first [popd] dip / - [23 18] [size] . i [41.0 [23 18]] swaack first [popd] dip / - [23 18] . size [41.0 [23 18]] swaack first [popd] dip / - 2 . [41.0 [23 18]] swaack first [popd] dip / - 2 [41.0 [23 18]] . swaack first [popd] dip / - [23 18] 41.0 [2] . first [popd] dip / - [23 18] 41.0 2 . [popd] dip / - [23 18] 41.0 2 [popd] . dip / - [23 18] 41.0 . popd 2 / - 41.0 . 2 / - 41.0 2 . / - 20.5 . - diff --git a/docs/sphinx_docs/notebooks/Square_Spiral.rst b/docs/sphinx_docs/notebooks/Square_Spiral.rst deleted file mode 100644 index 7b5e67a..0000000 --- a/docs/sphinx_docs/notebooks/Square_Spiral.rst +++ /dev/null @@ -1,421 +0,0 @@ -.. code:: ipython3 - - from notebook_preamble import J, V, define - -Square Spiral Example Joy Code -============================== - -Here is the example of Joy code from the ``README`` file: - -:: - - [[[abs]ii <=][[<>][pop !-]||]&&][[!-][[++]][[--]]ifte dip][[pop !-][--][++]ifte]ifte - -It might seem unreadable but with a little familiarity it becomes just -as legible as any other notation. Some layout helps: - -:: - - [ [[abs] ii <=] - [ - [<>] [pop !-] || - ] && - ] - [[ !-] [[++]] [[--]] ifte dip] - [[pop !-] [--] [++] ifte ] - ifte - -This function accepts two integers on the stack and increments or -decrements one of them such that the new pair of numbers is the next -coordinate pair in a square spiral (like the kind used to construct an -Ulam Spiral). - -Original Form -------------- - -It's adapted from `the original code on -StackOverflow `__: - - If all you're trying to do is generate the first N points in the - spiral (without the original problem's constraint of masking to an N - x M region), the code becomes very simple: - -:: - - void spiral(const int N) - { - int x = 0; - int y = 0; - for(int i = 0; i < N; ++i) - { - cout << x << '\t' << y << '\n'; - if(abs(x) <= abs(y) && (x != y || x >= 0)) - x += ((y >= 0) ? 1 : -1); - else - y += ((x >= 0) ? -1 : 1); - } - } - -Translation to Joy ------------------- - -I'm going to make a function that take two ints (``x`` and ``y``) and -generates the next pair, we'll turn it into a generator later using the -``x`` combinator. - -First Boolean Predicate -~~~~~~~~~~~~~~~~~~~~~~~ - -We need a function that computes ``abs(x) <= abs(y)``, we can use ``ii`` -to apply ``abs`` to both values and then compare them with ``<=``: - -:: - - [abs] ii <= - -I've defined two short-circuiting Boolean combinators ``&&`` and ``||`` -that each accept two quoted predicate programs, run the first, and -conditionally run the second only if required (to compute the final -Boolean value). They run their predicate arguments ``nullary``. - -.. code:: ipython3 - - define('&& [nullary] cons [nullary [0]] dip branch') - define('|| [nullary] cons [nullary] dip [1] branch') - -Given those, we can define ``x != y || x >= 0`` as: - -:: - - [<>] [pop 0 >=] || - -And ``(abs(x) <= abs(y) && (x != y || x >= 0))`` as: - -:: - - [[abs] ii <=] [[<>] [pop 0 >=] ||] && - -It's a little rough, but, as I say, with a little familiarity it becomes -legible. - -The Increment / Decrement Branches -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Turning to the branches of the main ``if`` statement: - -:: - - x += ((y >= 0) ? 1 : -1); - -Rewrite as a hybrid (pseudo-code) ``ifte`` expression: - -:: - - [y >= 0] [x += 1] [X -= 1] ifte - -Change each C phrase to Joy code: - -:: - - [0 >=] [[++] dip] [[--] dip] ifte - -Factor out the dip from each branch: - -:: - - [0 >=] [[++]] [[--]] ifte dip - -Similar logic applies to the other branch: - -:: - - y += ((x >= 0) ? -1 : 1); - - [x >= 0] [y -= 1] [y += 1] ifte - - [pop 0 >=] [--] [++] ifte - -"Not Negative" -~~~~~~~~~~~~~~ - -.. code:: ipython3 - - define('!- 0 >=') - -Putting the Pieces Together ---------------------------- - -We can assemble the three functions we just defined in quotes and give -them them to the ``ifte`` combinator. With some arrangement to show off -the symmetry of the two branches, we have: - -:: - - [[[abs] ii <=] [[<>] [pop !-] ||] &&] - [[ !-] [[++]] [[--]] ifte dip] - [[pop !-] [--] [++] ifte ] - ifte - -As I was writing this up I realized that, since the ``&&`` combinator -doesn't consume the stack (below its quoted args), I can unquote the -predicate, swap the branches, and use the ``branch`` combinator instead -of ``ifte``: - -:: - - [[abs] ii <=] [[<>] [pop !-] ||] && - [[pop !-] [--] [++] ifte ] - [[ !-] [[++]] [[--]] ifte dip] - branch - -.. code:: ipython3 - - define('spiral_next [[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte') - -Let's try it out: - -.. code:: ipython3 - - J('0 0 spiral_next') - - -.. parsed-literal:: - - 1 0 - - -.. code:: ipython3 - - J('1 0 spiral_next') - - -.. parsed-literal:: - - 1 -1 - - -.. code:: ipython3 - - J('1 -1 spiral_next') - - -.. parsed-literal:: - - 0 -1 - - -.. code:: ipython3 - - J('0 -1 spiral_next') - - -.. parsed-literal:: - - -1 -1 - - -Turning it into a Generator with ``x`` --------------------------------------- - -It can be used with the x combinator to make a kind of generator for -spiral square coordinates. - -We can use ``codireco`` to make a generator - -:: - - codireco ::= cons dip rest cons - -It will look like this: - -:: - - [value [F] codireco] - -Here's a trace of how it works: - -:: - - [0 [dup ++] codireco] . x - [0 [dup ++] codireco] . 0 [dup ++] codireco - [0 [dup ++] codireco] 0 . [dup ++] codireco - [0 [dup ++] codireco] 0 [dup ++] . codireco - [0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons - [0 [dup ++] codireco] [0 dup ++] . dip rest cons - . 0 dup ++ [0 [dup ++] codireco] rest cons - 0 . dup ++ [0 [dup ++] codireco] rest cons - 0 0 . ++ [0 [dup ++] codireco] rest cons - 0 1 . [0 [dup ++] codireco] rest cons - 0 1 [0 [dup ++] codireco] . rest cons - 0 1 [[dup ++] codireco] . cons - 0 [1 [dup ++] codireco] . - -But first we have to change the ``spiral_next`` function to work on a -quoted pair of integers, and leave a copy of the pair on the stack. -From: - -:: - - y x spiral_next - --------------------- - y' x' - -to: - -:: - - [x y] [spiral_next] infra - ------------------------------- - [x' y'] - -.. code:: ipython3 - - J('[0 0] [spiral_next] infra') - - -.. parsed-literal:: - - [0 1] - - -So our generator is: - -:: - - [[x y] [dup [spiral_next] infra] codireco] - -Or rather: - -:: - - [[0 0] [dup [spiral_next] infra] codireco] - -There is a function ``make_generator`` that will build the generator for -us out of the value and stepper function: - -:: - - [0 0] [dup [spiral_next] infra] make_generator - ---------------------------------------------------- - [[0 0] [dup [spiral_next] infra] codireco] - -Here it is in action: - -.. code:: ipython3 - - J('[0 0] [dup [spiral_next] infra] make_generator x x x x pop') - - -.. parsed-literal:: - - [0 0] [0 1] [-1 1] [-1 0] - - -Four ``x`` combinators, four pairs of coordinates. - -Conclusion ----------- - -So that's an example of Joy code. It's a straightforward translation of -the original. It's a little long for a single definition, you might -break it up like so: - -:: - - _spn_P ::= [[abs] ii <=] [[<>] [pop !-] ||] && - - _spn_T ::= [ !-] [[++]] [[--]] ifte dip - _spn_E ::= [pop !-] [--] [++] ifte - - spiral_next ::= _spn_P [_spn_E] [_spn_T] branch - -This way it's easy to see that the function is a branch with two -quasi-symmetrical paths. - -We then used this function to make a simple generator of coordinate -pairs, where the next pair in the series can be generated at any time by -using the ``x`` combinator on the generator (which is just a quoted -expression containing a copy of the current pair and the "stepper -function" to generate the next pair from that.) - -.. code:: ipython3 - - define('_spn_P [[abs] ii <=] [[<>] [pop !-] ||] &&') - define('_spn_T [!-] [[++]] [[--]] ifte dip') - define('_spn_E [pop !-] [--] [++] ifte') - define('spiral_next _spn_P [_spn_E] [_spn_T] branch') - -.. code:: ipython3 - - V('23 18 spiral_next') - - -.. parsed-literal:: - - . 23 18 spiral_next - 23 . 18 spiral_next - 23 18 . spiral_next - 23 18 . _spn_P [_spn_E] [_spn_T] branch - 23 18 . [[abs] ii <=] [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] . [[<>] [pop !-] ||] && [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . && [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[<>] [pop !-] ||] . [nullary] cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[<>] [pop !-] ||] [nullary] . cons [nullary [0]] dip branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] . [nullary [0]] dip branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [[[<>] [pop !-] ||] nullary] [nullary [0]] . dip branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] . nullary [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] . [stack] dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [stack] . dinfrirst [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [[abs] ii <=] [stack] . dip infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . stack [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [18 23] . [[abs] ii <=] infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [18 23] [[abs] ii <=] . infra first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . [abs] ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] . ii <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] . [dip] dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] [dip] . dupdip i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] . dip [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 . abs 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 . 18 [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . [abs] i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [abs] . i <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . abs <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 . <= [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - False . [18 23] swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - False [18 23] . swaack first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 [False] . first [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 False . [0] [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 False [0] . [[[<>] [pop !-] ||] nullary] branch [_spn_E] [_spn_T] branch - 23 18 False [0] [[[<>] [pop !-] ||] nullary] . branch [_spn_E] [_spn_T] branch - 23 18 . 0 [_spn_E] [_spn_T] branch - 23 18 0 . [_spn_E] [_spn_T] branch - 23 18 0 [_spn_E] . [_spn_T] branch - 23 18 0 [_spn_E] [_spn_T] . branch - 23 18 . _spn_E - 23 18 . [pop !-] [--] [++] ifte - 23 18 [pop !-] . [--] [++] ifte - 23 18 [pop !-] [--] . [++] ifte - 23 18 [pop !-] [--] [++] . ifte - 23 18 [pop !-] [--] [++] . [nullary not] dipd branch - 23 18 [pop !-] [--] [++] [nullary not] . dipd branch - 23 18 [pop !-] . nullary not [--] [++] branch - 23 18 [pop !-] . [stack] dinfrirst not [--] [++] branch - 23 18 [pop !-] [stack] . dinfrirst not [--] [++] branch - 23 18 [pop !-] [stack] . dip infra first not [--] [++] branch - 23 18 . stack [pop !-] infra first not [--] [++] branch - 23 18 [18 23] . [pop !-] infra first not [--] [++] branch - 23 18 [18 23] [pop !-] . infra first not [--] [++] branch - 23 18 . pop !- [18 23] swaack first not [--] [++] branch - 23 . !- [18 23] swaack first not [--] [++] branch - 23 . 0 >= [18 23] swaack first not [--] [++] branch - 23 0 . >= [18 23] swaack first not [--] [++] branch - True . [18 23] swaack first not [--] [++] branch - True [18 23] . swaack first not [--] [++] branch - 23 18 [True] . first not [--] [++] branch - 23 18 True . not [--] [++] branch - 23 18 False . [--] [++] branch - 23 18 False [--] . [++] branch - 23 18 False [--] [++] . branch - 23 18 . -- - 23 17 . - diff --git a/docs/sphinx_docs/notebooks/The_Four_Operations.rst b/docs/sphinx_docs/notebooks/The_Four_Operations.rst deleted file mode 100644 index 2dc77d3..0000000 --- a/docs/sphinx_docs/notebooks/The_Four_Operations.rst +++ /dev/null @@ -1,336 +0,0 @@ -The Four Fundamental Operations of Definite Action -================================================== - -All definite actions (computer program) can be defined by four -fundamental patterns of combination: - -1. Sequence -2. Branch -3. Loop -4. Parallel - -Sequence --------- - -Do one thing after another. In joy this is represented by putting two -symbols together, juxtaposition: - -:: - - foo bar - -Operations have inputs and outputs. The outputs of ``foo`` must be -compatible in “arity”, type, and shape with the inputs of ``bar``. - -Branch ------- - -Do one thing or another. - -:: - - boolean [F] [T] branch - - - t [F] [T] branch - ---------------------- - T - - - f [F] [T] branch - ---------------------- - F - - - branch == unit cons swap pick i - - boolean [F] [T] branch - boolean [F] [T] unit cons swap pick i - boolean [F] [[T]] cons swap pick i - boolean [[F] [T]] swap pick i - [[F] [T]] boolean pick i - [F-or-T] i - -Given some branch function ``G``: - -:: - - G == [F] [T] branch - -Used in a sequence like so: - -:: - - foo G bar - -The inputs and outputs of ``F`` and ``T`` must be compatible with the -outputs for ``foo`` and the inputs of ``bar``, respectively. - -:: - - foo F bar - - foo T bar - -``ifte`` -~~~~~~~~ - -Often it will be easier on the programmer to write branching code with -the predicate specified in a quote. The ``ifte`` combinator provides -this (``T`` for “then” and ``E`` for “else”): - -:: - - [P] [T] [E] ifte - -Defined in terms of ``branch``: - -:: - - ifte == [nullary not] dip branch - -In this case, ``P`` must be compatible with the stack and return a -Boolean value, and ``T`` and ``E`` both must be compatible with the -preceeding and following functions, as described above for ``F`` and -``T``. (Note that in the current implementation we are depending on -Python for the underlying semantics, so the Boolean value doesn’t *have* -to be Boolean because Python’s rules for “truthiness” will be used to -evaluate it. I reflect this in the structure of the stack effect comment -of ``branch``, it will only accept Boolean values, and in the definition -of ``ifte`` above by including ``not`` in the quote, which also has the -effect that the subject quotes are in the proper order for ``branch``.) - -Loop ----- - -Do one thing zero or more times. - -:: - - boolean [Q] loop - - - t [Q] loop - ---------------- - Q [Q] loop - - - ... f [Q] loop - -------------------- - ... - -The ``loop`` combinator generates a copy of itself in the true branch. -This is the hallmark of recursive defintions. In Thun there is no -equivalent to conventional loops. (There is, however, the ``x`` -combinator, defined as ``x == dup i``, which permits recursive -constructs that do not need to be directly self-referential, unlike -``loop`` and ``genrec``.) - -:: - - loop == [] swap [dup dip loop] cons branch - - boolean [Q] loop - boolean [Q] [] swap [dup dip loop] cons branch - boolean [] [Q] [dup dip loop] cons branch - boolean [] [[Q] dup dip loop] branch - -In action the false branch does nothing while the true branch does: - -:: - - t [] [[Q] dup dip loop] branch - [Q] dup dip loop - [Q] [Q] dip loop - Q [Q] loop - -Because ``loop`` expects and consumes a Boolean value, the ``Q`` -function must be compatible with the previous stack *and itself* with a -boolean flag for the next iteration: - -:: - - Q == G b - - Q [Q] loop - G b [Q] loop - G Q [Q] loop - G G b [Q] loop - G G Q [Q] loop - G G G b [Q] loop - G G G - -``while`` -~~~~~~~~~ - -Keep doing ``B`` *while* some predicate ``P`` is true. This is -convenient as the predicate function is made nullary automatically and -the body function can be designed without regard to leaving a Boolean -flag for the next iteration: - -:: - - [P] [B] while - -------------------------------------- - [P] nullary [B [P] nullary] loop - - - while == swap [nullary] cons dup dipd concat loop - - - [P] [B] while - [P] [B] swap [nullary] cons dup dipd concat loop - [B] [P] [nullary] cons dup dipd concat loop - [B] [[P] nullary] dup dipd concat loop - [B] [[P] nullary] [[P] nullary] dipd concat loop - [P] nullary [B] [[P] nullary] concat loop - [P] nullary [B [P] nullary] loop - -Parallel --------- - -The *parallel* operation indicates that two (or more) functions *do not -interfere* with each other and so can run in parallel. The main -difficulty in this sort of thing is orchestrating the recombining -(“join” or “wait”) of the results of the functions after they finish. - -The current implementaions and the following definitions *are not -actually parallel* (yet), but there is no reason they couldn’t be -reimplemented in terms of e.g. Python threads. I am not concerned with -performance of the system just yet, only the elegance of the code it -allows us to write. - -``cleave`` -~~~~~~~~~~ - -Joy has a few parallel combinators, the main one being ``cleave``: - -:: - - ... x [A] [B] cleave - --------------------------------------------------------- - ... [x ...] [A] infra first [x ...] [B] infra first - --------------------------------------------------------- - ... a b - -The ``cleave`` combinator expects a value and two quotes and it executes -each quote in “separate universes” such that neither can affect the -other, then it takes the first item from the stack in each universe and -replaces the value and quotes with their respective results. - -(I think this corresponds to the “fork” operator, the little -upward-pointed triangle, that takes two functions ``A :: x -> a`` and -``B :: x -> b`` and returns a function ``F :: x -> (a, b)``, in Conal -Elliott’s “Compiling to Categories” paper, et. al.) - -Just a thought, if you ``cleave`` two jobs and one requires more time to -finish than the other you’d like to be able to assign resources -accordingly so that they both finish at the same time. - -“Apply” Functions -~~~~~~~~~~~~~~~~~ - -There are also ``app2`` and ``app3`` which run a single quote on more -than one value: - -:: - - ... y x [Q] app2 - --------------------------------------------------------- - ... [y ...] [Q] infra first [x ...] [Q] infra first - - - ... z y x [Q] app3 - --------------------------------- - ... [z ...] [Q] infra first - [y ...] [Q] infra first - [x ...] [Q] infra first - -Because the quoted program can be ``i`` we can define ``cleave`` in -terms of ``app2``: - -:: - - cleave == [i] app2 [popd] dip - -(I’m not sure why ``cleave`` was specified to take that value, I may -make a combinator that does the same thing but without expecting a -value.) - -:: - - clv == [i] app2 - - [A] [B] clv - ------------------ - a b - -``map`` -~~~~~~~ - -The common ``map`` function in Joy should also be though of as a -*parallel* operator: - -:: - - [a b c ...] [Q] map - -There is no reason why the implementation of ``map`` couldn’t distribute -the ``Q`` function over e.g. a pool of worker CPUs. - -``pam`` -~~~~~~~ - -One of my favorite combinators, the ``pam`` combinator is just: - -:: - - pam == [i] map - -This can be used to run any number of programs separately on the current -stack and combine their (first) outputs in a result list. - -:: - - [[A] [B] [C] ...] [i] map - ------------------------------- - [ a b c ...] - -Handling Other Kinds of Join -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``cleave`` operators and others all have pretty brutal join -semantics: everything works and we always wait for every -sub-computation. We can imagine a few different potentially useful -patterns of “joining” results from parallel combinators. - -first-to-finish -^^^^^^^^^^^^^^^ - -Thinking about variations of ``pam`` there could be one that only -returns the first result of the first-to-finish sub-program, or the -stack could be replaced by its output stack. - -The other sub-programs would be cancelled. - -“Fulminators” -^^^^^^^^^^^^^ - -Also known as “Futures” or “Promises” (by *everybody* else. “Fulminators” -is what I was going to call them when I was thinking about implementing -them in Thun.) - -The runtime could be amended to permit “thunks” representing the results -of in-progress computations to be left on the stack and picked up by -subsequent functions. These would themselves be able to leave behind -more “thunks”, the values of which depend on the eventual resolution of -the values of the previous thunks. - -In this way you can create “chains” (and more complex shapes) out of -normal-looking code that consist of a kind of call-graph interspersed -with “asyncronous” … events? - -In any case, until I can find a rigorous theory that shows that this -sort of thing works perfectly in Joy code I’m not going to worry about -it. (And I think the Categories can deal with it anyhow? Incremental -evaluation, yeah?) diff --git a/docs/sphinx_docs/notebooks/Treestep.rst b/docs/sphinx_docs/notebooks/Treestep.rst deleted file mode 100644 index 6b9081f..0000000 --- a/docs/sphinx_docs/notebooks/Treestep.rst +++ /dev/null @@ -1,620 +0,0 @@ -Treating Trees II: ``treestep`` -=============================== - -Let’s consider a tree structure, similar to one described `“Why -functional programming matters” by John -Hughes `__, -that consists of a node value followed by zero or more child trees. (The -asterisk is meant to indicate the `Kleene -star `__.) - -:: - - tree = [] | [node tree*] - -In the spirit of ``step`` we are going to define a combinator -``treestep`` which expects a tree and three additional items: a -base-case function ``[B]``, and two quoted programs ``[N]`` and ``[C]``. - -:: - - tree [B] [N] [C] treestep - -If the current tree node is empty then just execute ``B``: - -:: - - [] [B] [N] [C] treestep - --------------------------- - [] B - -Otherwise, evaluate ``N`` on the node value, ``map`` the whole function -(abbreviated here as ``K``) over the child trees recursively, and then -combine the result with ``C``. - -:: - - [node tree*] [B] [N] [C] treestep - --------------------------------------- w/ K == [B] [N] [C] treestep - node N [tree*] [K] map C - -(Later on we’ll experiment with making ``map`` part of ``C`` so you can -use other combinators.) - -Derive the recursive function. ------------------------------- - -We can begin to derive it by finding the ``ifte`` stage that ``genrec`` -will produce. - -:: - - K == [not] [B] [R0] [R1] genrec - == [not] [B] [R0 [K] R1] ifte - -So we just have to derive ``J``: - -:: - - J == R0 [K] R1 - -The behavior of ``J`` is to accept a (non-empty) tree node and arrive at -the desired outcome. - -:: - - [node tree*] J - ------------------------------ - node N [tree*] [K] map C - -So ``J`` will have some form like: - -:: - - J == ... [N] ... [K] ... [C] ... - -Let’s dive in. First, unquote the node and ``dip`` ``N``. - -:: - - [node tree*] uncons [N] dip - node [tree*] [N] dip - node N [tree*] - -Next, ``map`` ``K`` over the child trees and combine with ``C``. - -:: - - node N [tree*] [K] map C - node N [tree*] [K] map C - node N [K.tree*] C - -So: - -:: - - J == uncons [N] dip [K] map C - -Plug it in and convert to ``genrec``: - -:: - - K == [not] [B] [J ] ifte - == [not] [B] [uncons [N] dip [K] map C] ifte - == [not] [B] [uncons [N] dip] [map C] genrec - -Extract the givens to parameterize the program. ------------------------------------------------ - -Working backwards: - -:: - - [not] [B] [uncons [N] dip] [map C] genrec - [B] [not] swap [uncons [N] dip] [map C] genrec - [B] [uncons [N] dip] [[not] swap] dip [map C] genrec - ^^^^^^^^^^^^^^^^ - [B] [[N] dip] [uncons] swoncat [[not] swap] dip [map C] genrec - [B] [N] [dip] cons [uncons] swoncat [[not] swap] dip [map C] genrec - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Extract a couple of auxiliary definitions: - -:: - - TS.0 == [[not] swap] dip - TS.1 == [dip] cons [uncons] swoncat - -:: - - [B] [N] TS.1 TS.0 [map C] genrec - [B] [N] [map C] [TS.1 TS.0] dip genrec - [B] [N] [C] [map] swoncat [TS.1 TS.0] dip genrec - -The givens are all to the left so we have our definition. - -(alternate) Extract the givens to parameterize the program. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Working backwards: - -:: - - [not] [B] [uncons [N] dip] [map C] genrec - [not] [B] [N] [dip] cons [uncons] swoncat [map C] genrec - [B] [N] [not] roll> [dip] cons [uncons] swoncat [map C] genrec - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Define ``treestep`` -------------------- - -.. code:: ipython2 - - from notebook_preamble import D, J, V, define, DefinitionWrapper - -.. code:: ipython2 - - 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 - - ''', D) - -Examples --------- - -Consider trees, the nodes of which are integers. We can find the sum of -all nodes in a tree with this function: - -:: - - sumtree == [pop 0] [] [sum +] treestep - -.. code:: ipython2 - - define('sumtree == [pop 0] [] [sum +] treestep') - -Running this function on an empty tree value gives zero: - -:: - - [] [pop 0] [] [sum +] treestep - ------------------------------------ - 0 - -.. code:: ipython2 - - J('[] sumtree') # Empty tree. - - -.. parsed-literal:: - - 0 - - -Running it on a non-empty node: - -:: - - [n tree*] [pop 0] [] [sum +] treestep - n [tree*] [[pop 0] [] [sum +] treestep] map sum + - n [ ... ] sum + - n m + - n+m - -.. code:: ipython2 - - J('[23] sumtree') # No child trees. - - -.. parsed-literal:: - - 23 - - -.. code:: ipython2 - - J('[23 []] sumtree') # Child tree, empty. - - -.. parsed-literal:: - - 23 - - -.. code:: ipython2 - - J('[23 [2 [4]] [3]] sumtree') # Non-empty child trees. - - -.. parsed-literal:: - - 32 - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] sumtree') # Etc... - - -.. parsed-literal:: - - 49 - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate "spelling". - - -.. parsed-literal:: - - 49 - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 23] [cons] treestep') # Replace each node. - - -.. parsed-literal:: - - [23 [23 [23] [23]] [23] [23 []]] - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep') - - -.. parsed-literal:: - - [1 [1 [1] [1]] [1] [1 []]] - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [] [pop 1] [cons] treestep sumtree') - - -.. parsed-literal:: - - 6 - - -.. code:: ipython2 - - J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function. - - -.. parsed-literal:: - - 6 - - -.. code:: ipython2 - - J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function. - - -.. parsed-literal:: - - 3 - - -Redefining the Ordered Binary Tree in terms of ``treestep``. ------------------------------------------------------------- - -:: - - Tree = [] | [[key value] left right] - -What kind of functions can we write for this with our ``treestep``? - -The pattern for processing a non-empty node is: - -:: - - node N [tree*] [K] map C - -Plugging in our BTree structure: - -:: - - [key value] N [left right] [K] map C - -Traversal -~~~~~~~~~ - -:: - - [key value] first [left right] [K] map i - key [value] [left right] [K] map i - key [left right] [K] map i - key [lkey rkey ] i - key lkey rkey - -This doesn’t quite work: - -.. code:: ipython2 - - J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] ["B"] [first] [i] treestep') - - -.. parsed-literal:: - - 3 'B' 'B' - - -Doesn’t work because ``map`` extracts the ``first`` item of whatever its -mapped function produces. We have to return a list, rather than -depositing our results directly on the stack. - -:: - - [key value] N [left right] [K] map C - - [key value] first [left right] [K] map flatten cons - key [left right] [K] map flatten cons - key [[lk] [rk] ] flatten cons - key [ lk rk ] cons - [key lk rk ] - -So: - -:: - - [] [first] [flatten cons] treestep - -.. code:: ipython2 - - J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first] [flatten cons] treestep') - - -.. parsed-literal:: - - [3 2 9 5 4 8 6 7] - - -There we go. - -In-order traversal -~~~~~~~~~~~~~~~~~~ - -From here: - -:: - - key [[lk] [rk]] C - key [[lk] [rk]] i - key [lk] [rk] roll< - [lk] [rk] key swons concat - [lk] [key rk] concat - [lk key rk] - -So: - -:: - - [] [i roll< swons concat] [first] treestep - -.. code:: ipython2 - - J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [uncons pop] [i roll< swons concat] treestep') - - -.. parsed-literal:: - - [2 3 4 5 6 7 8 9] - - -With ``treegrind``? -------------------- - -The ``treegrind`` function doesn’t include the ``map`` combinator, so -the ``[C]`` function must arrange to use some combinator on the quoted -recursive copy ``[K]``. With this function, the pattern for processing a -non-empty node is: - -:: - - node N [tree*] [K] C - -Plugging in our BTree structure: - -:: - - [key value] N [left right] [K] C - -.. code:: ipython2 - - J('[["key" "value"] ["left"] ["right"] ] ["B"] ["N"] ["C"] treegrind') - - -.. parsed-literal:: - - ['key' 'value'] 'N' [['left'] ['right']] [[not] ['B'] [uncons ['N'] dip] ['C'] genrec] 'C' - - -``treegrind`` with ``step`` ---------------------------- - -Iteration through the nodes - -.. code:: ipython2 - - J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] ["N"] [step] treegrind') - - -.. parsed-literal:: - - [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. - -.. code:: ipython2 - - J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind') - - -.. parsed-literal:: - - 44 - - -Rebuild the tree using ``map`` (imitating ``treestep``.) - -.. code:: ipython2 - - J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind') - - -.. parsed-literal:: - - [[103 0] [[102 0] [] []] [[109 0] [[105 0] [[104 0] [] []] [[108 0] [[106 0] [] [[107 0] [] []]] []]] []]] - - -Do we have the flexibility to reimplement ``Tree-get``? -------------------------------------------------------- - -I think we do: - -:: - - [B] [N] [C] treegrind - -We’ll start by saying that the base-case (the key is not in the tree) is -user defined, and the per-node function is just the query key literal: - -:: - - [B] [query_key] [C] treegrind - -This means we just have to define ``C`` from: - -:: - - [key value] query_key [left right] [K] C - -Let’s try ``cmp``: - -:: - - C == P [T>] [E] [T<] cmp - - [key value] query_key [left right] [K] P [T>] [E] [T<] cmp - -The predicate ``P`` -~~~~~~~~~~~~~~~~~~~ - -Seems pretty easy (we must preserve the value in case the keys are -equal): - -:: - - [key value] query_key [left right] [K] P - [key value] query_key [left right] [K] roll< - [key value] [left right] [K] query_key [roll< uncons swap] dip - - [key value] [left right] [K] roll< uncons swap query_key - [left right] [K] [key value] uncons swap query_key - [left right] [K] key [value] swap query_key - [left right] [K] [value] key query_key - - P == roll< [roll< uncons swap] dip - -(Possibly with a swap at the end? Or just swap ``T<`` and ``T>``.) - -So now: - -:: - - [left right] [K] [value] key query_key [T>] [E] [T<] cmp - -Becomes one of these three: - -:: - - [left right] [K] [value] T> - [left right] [K] [value] E - [left right] [K] [value] T< - -``E`` -~~~~~ - -Easy. - -:: - - E == roll> popop first - -``T<`` and ``T>`` -~~~~~~~~~~~~~~~~~ - -:: - - T< == pop [first] dip i - T> == pop [second] dip i - -Putting it together -------------------- - -:: - - 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 - -To me, that seems simpler than the ``genrec`` version. - -.. code:: ipython2 - - DefinitionWrapper.add_definitions(''' - - 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 - - ''', D) - -.. code:: ipython2 - - J('''\ - - [[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]] - - [] [5] Tree-get - - ''') - - -.. parsed-literal:: - - 15 - - -.. code:: ipython2 - - J('''\ - - [[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]] - - [pop "nope"] [25] Tree-get - - ''') - - -.. parsed-literal:: - - 'nope' - diff --git a/docs/sphinx_docs/notebooks/TypeChecking.rst b/docs/sphinx_docs/notebooks/TypeChecking.rst deleted file mode 100644 index cd85c67..0000000 --- a/docs/sphinx_docs/notebooks/TypeChecking.rst +++ /dev/null @@ -1,171 +0,0 @@ -Type Checking -============= - -.. code:: ipython2 - - import logging, sys - - logging.basicConfig( - format='%(message)s', - stream=sys.stdout, - level=logging.INFO, - ) - -.. code:: ipython2 - - from joy.utils.types import ( - doc_from_stack_effect, - infer, - reify, - unify, - FUNCTIONS, - JoyTypeError, - ) - -.. code:: ipython2 - - D = FUNCTIONS.copy() - del D['product'] - globals().update(D) - -An Example ----------- - -.. code:: ipython2 - - fi, fo = infer(pop, swap, rolldown, rrest, ccons)[0] - - -.. parsed-literal:: - - 25 (--) ∘ pop swap rolldown rrest ccons - 28 (a1 --) ∘ swap rolldown rrest ccons - 31 (a3 a2 a1 -- a2 a3) ∘ rolldown rrest ccons - 34 (a4 a3 a2 a1 -- a2 a3 a4) ∘ rrest ccons - 37 ([a4 a5 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ ccons - 40 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘ - - -.. code:: ipython2 - - print doc_from_stack_effect(fi, fo) - - -.. parsed-literal:: - - ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) - - -.. code:: ipython2 - - from joy.parser import text_to_expression - from joy.utils.stack import stack_to_string - - -.. code:: ipython2 - - e = text_to_expression('0 1 2 [3 4]') # reverse order - print stack_to_string(e) - - -.. parsed-literal:: - - [3 4] 2 1 0 - - -.. code:: ipython2 - - u = unify(e, fi)[0] - u - - - - -.. parsed-literal:: - - {a1: 0, a2: 1, a3: 2, a4: 3, a5: 4, s2: (), s1: ()} - - - -.. code:: ipython2 - - g = reify(u, (fi, fo)) - print doc_from_stack_effect(*g) - - -.. parsed-literal:: - - (... [3 4 ] 2 1 0 -- ... [1 2 ]) - - -Unification Works “in Reverse” ------------------------------- - -.. code:: ipython2 - - e = text_to_expression('[2 3]') - -.. code:: ipython2 - - u = unify(e, fo)[0] # output side, not input side - u - - - - -.. parsed-literal:: - - {a2: 2, a3: 3, s2: (), s1: ()} - - - -.. code:: ipython2 - - g = reify(u, (fi, fo)) - print doc_from_stack_effect(*g) - - -.. parsed-literal:: - - (... [a4 a5 ] 3 2 a1 -- ... [2 3 ]) - - -Failing a Check ---------------- - -.. code:: ipython2 - - fi, fo = infer(dup, mul)[0] - - -.. parsed-literal:: - - 25 (--) ∘ dup mul - 28 (a1 -- a1 a1) ∘ mul - 31 (f1 -- f2) ∘ - 31 (i1 -- i2) ∘ - - -.. code:: ipython2 - - e = text_to_expression('"two"') - print stack_to_string(e) - - -.. parsed-literal:: - - 'two' - - -.. code:: ipython2 - - try: - unify(e, fi) - except JoyTypeError, err: - print err - - -.. parsed-literal:: - - Cannot unify 'two' and f1. - diff --git a/docs/sphinx_docs/notebooks/Types.rst b/docs/sphinx_docs/notebooks/Types.rst deleted file mode 100644 index 4c91600..0000000 --- a/docs/sphinx_docs/notebooks/Types.rst +++ /dev/null @@ -1,2968 +0,0 @@ -The Blissful Elegance of Typing Joy -=================================== - -This notebook presents a simple type inferencer for Joy code. It can -infer the stack effect of most Joy expressions. It’s built largely by -means of existing ideas and research. (A great overview of the existing -knowledge is a talk `“Type Inference in Stack-Based Programming -Languages” `__ -given by Rob Kleffner on or about 2017-03-10 as part of a course on the -history of programming languages.) - -The notebook starts with a simple inferencer based on the work of Jaanus -Pöial which we then progressively elaborate to cover more Joy semantics. -Along the way we write a simple “compiler” that emits Python code for -what I like to call Yin functions. (Yin functions are those that only -rearrange values in stacks, as opposed to Yang functions that actually -work on the values themselves.) - -Part I: Pöial’s Rules ---------------------- - -`“Typing Tools for Typeless Stack Languages” by Jaanus -Pöial `__ - -:: - - @INPROCEEDINGS{Pöial06typingtools, - author = {Jaanus Pöial}, - title = {Typing tools for typeless stack languages}, - booktitle = {In 23rd Euro-Forth Conference}, - year = {2006}, - pages = {40--46} - } - -First Rule -~~~~~~~~~~ - -This rule deals with functions (and literals) that put items on the -stack ``(-- d)``: - -:: - - (a -- b)∘(-- d) - --------------------- - (a -- b d) - -Second Rule -~~~~~~~~~~~ - -This rule deals with functions that consume items from the stack -``(a --)``: - -:: - - (a --)∘(c -- d) - --------------------- - (c a -- d) - -Third Rule -~~~~~~~~~~ - -The third rule is actually two rules. These two rules deal with -composing functions when the second one will consume one of items the -first one produces. The two types must be -`unified `__ -or a type conflict declared. - -:: - - (a -- b t[i])∘(c u[j] -- d) t <= u (t is subtype of u) - ------------------------------- - (a -- b )∘(c -- d) t[i] == t[k] == u[j] - ^ - - (a -- b t[i])∘(c u[j] -- d) u <= t (u is subtype of t) - ------------------------------- - (a -- b )∘(c -- d) t[i] == u[k] == u[j] - -Let’s work through some examples by hand to develop an intuition for the -algorithm. - -There’s a function in one of the other notebooks. - -:: - - F == pop swap roll< rest rest cons cons - -It’s all “stack chatter” and list manipulation so we should be able to -deduce its type. - -Stack Effect Comments -~~~~~~~~~~~~~~~~~~~~~ - -Joy function types will be represented by Forth-style stack effect -comments. I’m going to use numbers instead of names to keep track of the -stack arguments. (A little bit like `De Bruijn -index `__, at least it -reminds me of them): - -:: - - pop (1 --) - - swap (1 2 -- 2 1) - - roll< (1 2 3 -- 2 3 1) - -These commands alter the stack but don’t “look at” the values so these -numbers represent an “Any type”. - -``pop swap`` -~~~~~~~~~~~~ - -:: - - (1 --) (1 2 -- 2 1) - -Here we encounter a complication. The argument numbers need to be made -unique among both sides. For this let’s change ``pop`` to use 0: - -:: - - (0 --) (1 2 -- 2 1) - -Following the second rule: - -:: - - (1 2 0 -- 2 1) - -``pop∘swap roll<`` -~~~~~~~~~~~~~~~~~~ - -:: - - (1 2 0 -- 2 1) (1 2 3 -- 2 3 1) - -Let’s re-label them: - -:: - - (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b) - -Now we follow the rules. - -We must unify ``1a`` and ``3b``, and ``2a`` and ``2b``, replacing the -terms in the forms: - -:: - - (1a 2a 0a -- 2a 1a) (1b 2b 3b -- 2b 3b 1b) - w/ {1a: 3b} - (3b 2a 0a -- 2a ) (1b 2b -- 2b 3b 1b) - w/ {2a: 2b} - (3b 2b 0a -- ) (1b -- 2b 3b 1b) - -Here we must apply the second rule: - -:: - - (3b 2b 0a --) (1b -- 2b 3b 1b) - ----------------------------------- - (1b 3b 2b 0a -- 2b 3b 1b) - -Now we de-label the type, uh, labels: - -:: - - (1b 3b 2b 0a -- 2b 3b 1b) - - w/ { - 1b: 1, - 3b: 2, - 2b: 3, - 0a: 0, - } - - (1 2 3 0 -- 3 2 1) - -And now we have the stack effect comment for ``pop∘swap∘roll<``. - -Compiling ``pop∘swap∘roll<`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The simplest way to “compile” this function would be something like: - -.. code:: ipython2 - - def poswrd(s, e, d): - return rolldown(*swap(*pop(s, e, d))) - -However, internally this function would still be allocating tuples -(stack cells) and doing other unnecesssary work. - -Looking ahead for a moment, from the stack effect comment: - -:: - - (1 2 3 0 -- 3 2 1) - -We should be able to directly write out a Python function like: - -.. code:: ipython2 - - def poswrd(stack): - (_, (a, (b, (c, stack)))) = stack - return (c, (b, (a, stack))) - -This eliminates the internal work of the first version. Because this -function only rearranges the stack and doesn’t do any actual processing -on the stack items themselves all the information needed to implement it -is in the stack effect comment. - -Functions on Stacks -~~~~~~~~~~~~~~~~~~~ - -These are slightly tricky. - -:: - - rest ( [1 ...] -- [...] ) - - cons ( 1 [...] -- [1 ...] ) - -``pop∘swap∘roll< rest`` -~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - (1 2 3 0 -- 3 2 1) ([1 ...] -- [...]) - -Re-label (instead of adding left and right tags I’m just taking the next -available index number for the right-side stack effect comment): - -:: - - (1 2 3 0 -- 3 2 1) ([4 ...] -- [...]) - -Unify and update: - -:: - - (1 2 3 0 -- 3 2 1) ([4 ...] -- [...]) - w/ {1: [4 ...]} - ([4 ...] 2 3 0 -- 3 2 ) ( -- [...]) - -Apply the first rule: - -:: - - ([4 ...] 2 3 0 -- 3 2) (-- [...]) - --------------------------------------- - ([4 ...] 2 3 0 -- 3 2 [...]) - -And there we are. - -``pop∘swap∘roll<∘rest rest`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Let’s do it again. - -:: - - ([4 ...] 2 3 0 -- 3 2 [...]) ([1 ...] -- [...]) - -Re-label (the tails of the lists on each side each get their own label): - -:: - - ([4 .0.] 2 3 0 -- 3 2 [.0.]) ([5 .1.] -- [.1.]) - -Unify and update (note the opening square brackets have been omited in -the substitution dict, this is deliberate and I’ll explain below): - -:: - - ([4 .0.] 2 3 0 -- 3 2 [.0.] ) ([5 .1.] -- [.1.]) - w/ { .0.] : 5 .1.] } - ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.]) - -How do we find ``.0.]`` in ``[4 .0.]`` and replace it with ``5 .1.]`` -getting the result ``[4 5 .1.]``? This might seem hard, but because the -underlying structure of the Joy list is a cons-list in Python it’s -actually pretty easy. I’ll explain below. - -Next we unify and find our two terms are the same already: ``[5 .1.]``: - -:: - - ([4 5 .1.] 2 3 0 -- 3 2 [5 .1.]) ([5 .1.] -- [.1.]) - -Giving us: - -:: - - ([4 5 .1.] 2 3 0 -- 3 2) (-- [.1.]) - -From here we apply the first rule and get: - -:: - - ([4 5 .1.] 2 3 0 -- 3 2 [.1.]) - -Cleaning up the labels: - -:: - - ([4 5 ...] 2 3 1 -- 3 2 [...]) - -This is the stack effect of ``pop∘swap∘roll<∘rest∘rest``. - -``pop∘swap∘roll<∘rest∘rest cons`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -:: - - ([4 5 ...] 2 3 1 -- 3 2 [...]) (1 [...] -- [1 ...]) - -Re-label: - -:: - - ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.]) - -Unify: - -:: - - ([4 5 .1.] 2 3 1 -- 3 2 [.1.]) (6 [.2.] -- [6 .2.]) - w/ { .1.] : .2.] } - ([4 5 .2.] 2 3 1 -- 3 2 ) (6 -- [6 .2.]) - w/ {2: 6} - ([4 5 .2.] 6 3 1 -- 3 ) ( -- [6 .2.]) - -First rule: - -:: - - ([4 5 .2.] 6 3 1 -- 3 [6 .2.]) - -Re-label: - -:: - - ([4 5 ...] 2 3 1 -- 3 [2 ...]) - -Done. - -``pop∘swap∘roll<∘rest∘rest∘cons cons`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -One more time. - -:: - - ([4 5 ...] 2 3 1 -- 3 [2 ...]) (1 [...] -- [1 ...]) - -Re-label: - -:: - - ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.]) - -Unify: - -:: - - ([4 5 .1.] 2 3 1 -- 3 [2 .1.]) (6 [.2.] -- [6 .2.] ) - w/ { .2.] : 2 .1.] } - ([4 5 .1.] 2 3 1 -- 3 ) (6 -- [6 2 .1.]) - w/ {3: 6} - ([4 5 .1.] 2 6 1 -- ) ( -- [6 2 .1.]) - -First or second rule: - -:: - - ([4 5 .1.] 2 6 1 -- [6 2 .1.]) - -Clean up the labels: - -:: - - ([4 5 ...] 2 3 1 -- [3 2 ...]) - -And there you have it, the stack effect for -``pop∘swap∘roll<∘rest∘rest∘cons∘cons``. - -:: - - ([4 5 ...] 2 3 1 -- [3 2 ...]) - -From this stack effect comment it should be possible to construct the -following Python code: - -.. code:: ipython2 - - def F(stack): - (_, (d, (c, ((a, (b, S0)), stack)))) = stack - return (d, (c, S0)), stack - -Part II: Implementation ------------------------ - -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 - - roll_dn = (1, 2, 3), (2, 3, 1) - - pop = (1,), () - - swap = (1, 2), (2, 1) - -``compose()`` -~~~~~~~~~~~~~ - -.. code:: ipython2 - - def compose(f, g): - - (f_in, f_out), (g_in, g_out) = f, g - - # First rule. - # - # (a -- b) (-- d) - # --------------------- - # (a -- b d) - - if not g_in: - - fg_in, fg_out = f_in, f_out + g_out - - # Second rule. - # - # (a --) (c -- d) - # --------------------- - # (c a -- d) - - elif not f_out: - - fg_in, fg_out = g_in + f_in, g_out - - else: # Unify, update, recur. - - fo, gi = f_out[-1], g_in[-1] - - 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)) - - f_g = (f_in, f_out[:-1]), (g_in[:-1], g_out) - - if s: f_g = update(s, f_g) - - fg_in, fg_out = compose(*f_g) - - return fg_in, fg_out - -``unify()`` -~~~~~~~~~~~ - -.. code:: ipython2 - - 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 - - return s - -``update()`` -~~~~~~~~~~~~ - -.. code:: ipython2 - - def update(s, term): - if not isinstance(term, tuple): - return s.get(term, term) - return tuple(update(s, inner) for inner in term) - -``relabel()`` -~~~~~~~~~~~~~ - -.. code:: ipython2 - - 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) - - relabel(pop, swap) - - - - -.. parsed-literal:: - - (((1,), ()), ((1001, 1002), (1002, 1001))) - - - -``delabel()`` -~~~~~~~~~~~~~ - -.. code:: ipython2 - - 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 - - delabel(relabel(pop, swap)) - - - - -.. parsed-literal:: - - (((0,), ()), ((1, 2), (2, 1))) - - - -``C()`` -~~~~~~~ - -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 - - def C(f, g): - f, g = relabel(f, g) - fg = compose(f, g) - return delabel(fg) - -Let’s try it out. - -.. code:: ipython2 - - C(pop, swap) - - - - -.. parsed-literal:: - - ((1, 2, 0), (2, 1)) - - - -.. code:: ipython2 - - C(C(pop, swap), roll_dn) - - - - -.. parsed-literal:: - - ((3, 1, 2, 0), (2, 1, 3)) - - - -.. code:: ipython2 - - C(swap, roll_dn) - - - - -.. parsed-literal:: - - ((2, 0, 1), (1, 0, 2)) - - - -.. code:: ipython2 - - C(pop, C(swap, roll_dn)) - - - - -.. parsed-literal:: - - ((3, 1, 2, 0), (2, 1, 3)) - - - -.. code:: ipython2 - - poswrd = reduce(C, (pop, swap, roll_dn)) - poswrd - - - - -.. parsed-literal:: - - ((3, 1, 2, 0), (2, 1, 3)) - - - -Stack Functions -~~~~~~~~~~~~~~~ - -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 - - rest = ((1, 2),), (2,) - - cons = (1, 2), ((1, 2),) - -.. code:: ipython2 - - C(poswrd, rest) - - - - -.. parsed-literal:: - - (((3, 4), 1, 2, 0), (2, 1, 4)) - - - -Compare this to the stack effect comment we wrote above: - -:: - - (( (3, 4), 1, 2, 0 ), ( 2, 1, 4 )) - ( [4 ...] 2 3 0 -- 3 2 [...]) - -The translation table, if you will, would be: - -:: - - { - 3: 4, - 4: ...], - 1: 2, - 2: 3, - 0: 0, - } - -.. code:: ipython2 - - F = reduce(C, (pop, swap, roll_dn, rest, rest, cons, cons)) - - F - - - - -.. parsed-literal:: - - (((3, (4, 5)), 1, 2, 0), ((2, (1, 5)),)) - - - -Compare with the stack effect comment and you can see it works fine: - -:: - - ([4 5 ...] 2 3 1 -- [3 2 ...]) - 3 4 5 1 2 0 2 1 5 - -Dealing with ``cons`` and ``uncons`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -However, if we try to compose e.g. ``cons`` and ``uncons`` it won’t -work: - -.. code:: ipython2 - - uncons = ((1, 2),), (1, 2) - -.. code:: ipython2 - - try: - C(cons, uncons) - except Exception, e: - print e - - -.. parsed-literal:: - - Cannot unify (1, 2) and (1001, 1002). - - -``unify()`` version 2 -^^^^^^^^^^^^^^^^^^^^^ - -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 - - 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 - - elif isinstance(v, int): - s[v] = u - - 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. - - (a, b), (c, d) = u, v - s = unify(a, c, s) - if s != False: - s = unify(b, d, s) - else: - s = False - - return s - -.. code:: ipython2 - - C(cons, uncons) - - - - -.. parsed-literal:: - - ((0, 1), (0, 1)) - - - -Part III: Compiling Yin Functions ---------------------------------- - -Now consider the Python function we would like to derive: - -.. code:: ipython2 - - 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: - -.. code:: ipython2 - - F[0] - - - - -.. parsed-literal:: - - ((3, (4, 5)), 1, 2, 0) - - - -The stack-de-structuring tuple has nearly the same form as our input -stack effect comment tuple, just in the reverse order: - -:: - - (_, (d, (c, ((a, (b, S0)), stack)))) - -Remove the punctuation: - -:: - - _ d c (a, (b, S0)) - -Reverse the order and compare: - -:: - - (a, (b, S0)) c d _ - ((3, (4, 5 )), 1, 2, 0) - -Eh? - -And the return tuple - -.. code:: ipython2 - - F[1] - - - - -.. parsed-literal:: - - ((2, (1, 5)),) - - - -is similar to the output stack effect comment tuple: - -:: - - ((d, (c, S0)), stack) - ((2, (1, 5 )), ) - -This should make it pretty easy to write a Python function that accepts -the stack effect comment tuples and returns a new Python function -(either as a string of code or a function object ready to use) that -performs the semantics of that Joy function (described by the stack -effect.) - -Python Identifiers -~~~~~~~~~~~~~~~~~~ - -We want to substitute Python identifiers for the integers. I’m going to -repurpose ``joy.parser.Symbol`` class for this: - -.. code:: ipython2 - - from collections import defaultdict - from joy.parser import Symbol - - - 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) - -``doc_from_stack_effect()`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -As a convenience I’ve implemented a function to convert the Python stack -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 - - 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) - -``compile_()`` -~~~~~~~~~~~~~~ - -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 - - 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: - -.. code:: ipython2 - - source = compile_('F', F) - - print source - - -.. parsed-literal:: - - def F(stack): - """([3 4 .5.] 1 2 0 -- [2 1 .5.])""" - (a5, (a4, (a3, ((a0, (a1, a2)), stack)))) = stack - return ((a4, (a3, a2)), stack) - - -Compare: - -.. code:: ipython2 - - def F_python(stack): - (_, (d, (c, ((a, (b, S0)), stack)))) = stack - return ((d, (c, S0)), stack) - -Next steps: - -.. code:: ipython2 - - L = {} - - eval(compile(source, '__main__', 'single'), {}, L) - - L['F'] - - - - -.. parsed-literal:: - - - - - -Let’s try it out: - -.. code:: ipython2 - - from notebook_preamble import D, J, V - from joy.library import SimpleFunctionWrapper - -.. code:: ipython2 - - D['F'] = SimpleFunctionWrapper(L['F']) - -.. code:: ipython2 - - J('[4 5 ...] 2 3 1 F') - - -.. parsed-literal:: - - [3 2 ...] - - -With this, we have a partial Joy compiler that works on the subset of -Joy functions that manipulate stacks (both what I call “stack chatter” -and the ones that manipulate stacks on the stack.) - -I’m probably going to modify the definition wrapper code to detect -definitions that can be compiled by this partial compiler and do it -automatically. It might be a reasonable idea to detect sequences of -compilable functions in definitions that have uncompilable functions in -them and just compile those. However, if your library is well-factored -this might be less helpful. - -Compiling Library Functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We can use ``compile_()`` to generate many primitives in the library -from their stack effect comments: - -.. code:: ipython2 - - def defs(): - - rolldown = (1, 2, 3), (2, 3, 1) - - rollup = (1, 2, 3), (3, 1, 2) - - pop = (1,), () - - swap = (1, 2), (2, 1) - - rest = ((1, 2),), (2,) - - rrest = C(rest, rest) - - cons = (1, 2), ((1, 2),) - - uncons = ((1, 2),), (1, 2) - - swons = C(swap, cons) - - return locals() - -.. code:: ipython2 - - for name, stack_effect_comment in sorted(defs().items()): - print - print compile_(name, stack_effect_comment) - print - - -.. parsed-literal:: - - - def cons(stack): - """(1 2 -- [1 .2.])""" - (a1, (a0, stack)) = stack - return ((a0, a1), stack) - - - def pop(stack): - """(1 --)""" - (a0, stack) = stack - return stack - - - def rest(stack): - """([1 .2.] -- 2)""" - ((a0, a1), stack) = stack - return (a1, stack) - - - def rolldown(stack): - """(1 2 3 -- 2 3 1)""" - (a2, (a1, (a0, stack))) = stack - return (a0, (a2, (a1, stack))) - - - def rollup(stack): - """(1 2 3 -- 3 1 2)""" - (a2, (a1, (a0, stack))) = stack - return (a1, (a0, (a2, stack))) - - - def rrest(stack): - """([0 1 .2.] -- 2)""" - ((a0, (a1, a2)), stack) = stack - return (a2, stack) - - - def swap(stack): - """(1 2 -- 2 1)""" - (a1, (a0, stack)) = stack - return (a0, (a1, stack)) - - - def swons(stack): - """(0 1 -- [1 .0.])""" - (a1, (a0, stack)) = stack - return ((a1, a0), stack) - - - def uncons(stack): - """([1 .2.] -- 1 2)""" - ((a0, a1), stack) = stack - return (a1, (a0, stack)) - - - -Part IV: Types and Subtypes of Arguments ----------------------------------------- - -So far we have dealt with types of functions, those dealing with simple -stack manipulation. Let’s extend our machinery to deal with types of -arguments. - -“Number” Type -~~~~~~~~~~~~~ - -Consider the definition of ``sqr``: - -:: - - sqr == dup mul - -The ``dup`` function accepts one *anything* and returns two of that: - -:: - - dup (1 -- 1 1) - -And ``mul`` accepts two “numbers” (we’re ignoring ints vs. floats -vs. complex, etc., for now) and returns just one: - -:: - - mul (n n -- n) - -So we’re composing: - -:: - - (1 -- 1 1)∘(n n -- n) - -The rules say we unify 1 with ``n``: - -:: - - (1 -- 1 1)∘(n n -- n) - --------------------------- w/ {1: n} - (1 -- 1 )∘(n -- n) - -This involves detecting that “Any type” arguments can accept “numbers”. -If we were composing these functions the other way round this is still -the case: - -:: - - (n n -- n)∘(1 -- 1 1) - --------------------------- w/ {1: n} - (n n -- )∘( -- n n) - -The important thing here is that the mapping is going the same way in -both cases, from the “any” integer to the number - -Distinguishing Numbers -~~~~~~~~~~~~~~~~~~~~~~ - -We should also mind that the number that ``mul`` produces is not -(necessarily) the same as either of its inputs, which are not -(necessarily) the same as each other: - -:: - - mul (n2 n1 -- n3) - - - (1 -- 1 1)∘(n2 n1 -- n3) - -------------------------------- w/ {1: n2} - (n2 -- n2 )∘(n2 -- n3) - - - (n2 n1 -- n3)∘(1 -- 1 1 ) - -------------------------------- w/ {1: n3} - (n2 n1 -- )∘( -- n3 n3) - -Distinguishing Types -~~~~~~~~~~~~~~~~~~~~ - -So we need separate domains of “any” numbers and “number” numbers, and -we need to be able to ask the order of these domains. Now the notes on -the right side of rule three make more sense, eh? - -:: - - (a -- b t[i])∘(c u[j] -- d) t <= u (t is subtype of u) - ------------------------------- - (a -- b )∘(c -- d) t[i] == t[k] == u[j] - ^ - - (a -- b t[i])∘(c u[j] -- d) u <= t (u is subtype of t) - ------------------------------- - (a -- b )∘(c -- d) t[i] == u[k] == u[j] - -The indices ``i``, ``k``, and ``j`` are the number part of our labels -and ``t`` and ``u`` are the domains. - -By creative use of Python’s “double underscore” methods we can define a -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 - - class AnyJoyType(object): - - prefix = 'a' - - def __init__(self, number): - self.number = 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 __ge__(self, other): - return issubclass(other.__class__, self.__class__) - - def __add__(self, other): - return self.__class__(self.number + other) - __radd__ = __add__ - - def __hash__(self): - return hash(repr(self)) - - - class NumberJoyType(AnyJoyType): prefix = 'n' - class FloatJoyType(NumberJoyType): prefix = 'f' - class IntJoyType(FloatJoyType): prefix = 'i' - - - class StackJoyType(AnyJoyType): - prefix = 's' - - - _R = range(10) - A = map(AnyJoyType, _R) - N = map(NumberJoyType, _R) - S = map(StackJoyType, _R) - -Mess with it a little: - -.. code:: ipython2 - - from itertools import permutations - -“Any” types can be specialized to numbers and stacks, but not vice -versa: - -.. code:: ipython2 - - for a, b in permutations((A[0], N[0], S[0]), 2): - print a, '>=', b, '->', a >= b - - -.. parsed-literal:: - - a0 >= n0 -> True - a0 >= s0 -> True - n0 >= a0 -> False - n0 >= s0 -> False - s0 >= a0 -> False - s0 >= n0 -> False - - -Our crude `Numerical -Tower `__ of *numbers* > -*floats* > *integers* works as well (but we’re not going to use it yet): - -.. code:: ipython2 - - for a, b in permutations((A[0], N[0], FloatJoyType(0), IntJoyType(0)), 2): - print a, '>=', b, '->', a >= b - - -.. parsed-literal:: - - a0 >= n0 -> True - a0 >= f0 -> True - a0 >= i0 -> True - n0 >= a0 -> False - n0 >= f0 -> True - n0 >= i0 -> True - f0 >= a0 -> False - f0 >= n0 -> False - f0 >= i0 -> True - i0 >= a0 -> False - i0 >= n0 -> False - i0 >= f0 -> False - - -Typing ``sqr`` -~~~~~~~~~~~~~~ - -.. code:: ipython2 - - dup = (A[1],), (A[1], A[1]) - - mul = (N[1], N[2]), (N[3],) - -.. code:: ipython2 - - dup - - - - -.. parsed-literal:: - - ((a1,), (a1, a1)) - - - -.. code:: ipython2 - - mul - - - - -.. parsed-literal:: - - ((n1, n2), (n3,)) - - - -Modifying the Inferencer -~~~~~~~~~~~~~~~~~~~~~~~~ - -Re-labeling still works fine: - -.. code:: ipython2 - - foo = relabel(dup, mul) - - foo - - - - -.. parsed-literal:: - - (((a1,), (a1, a1)), ((n1001, n1002), (n1003,))) - - - -``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”. - -.. code:: ipython2 - - from collections import 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 - - 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) - -.. code:: ipython2 - - delabel(foo) - - - - -.. parsed-literal:: - - (((a1,), (a1, a1)), ((n1, n2), (n3,))) - - - -``unify()`` version 3 -^^^^^^^^^^^^^^^^^^^^^ - -.. code:: ipython2 - - 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: - -.. code:: ipython2 - - def defs(): - - 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]) - - pop = (A[1],), () - - popop = (A[2], A[1],), () - - popd = (A[2], A[1],), (A[1],) - - popdd = (A[3], A[2], A[1],), (A[2], A[1],) - - swap = (A[1], A[2]), (A[2], A[1]) - - rest = ((A[1], S[1]),), (S[1],) - - rrest = C(rest, rest) - - cons = (A[1], S[1]), ((A[1], S[1]),) - - ccons = C(cons, cons) - - uncons = ((A[1], S[1]),), (A[1], S[1]) - - swons = C(swap, cons) - - dup = (A[1],), (A[1], A[1]) - - dupd = (A[2], A[1]), (A[2], A[2], A[1]) - - mul = (N[1], N[2]), (N[3],) - - sqrt = C(dup, mul) - - first = ((A[1], S[1]),), (A[1],) - - second = C(rest, first) - - third = C(rest, second) - - tuck = (A[2], A[1]), (A[1], A[2], A[1]) - - over = (A[2], A[1]), (A[2], A[1], A[2]) - - succ = pred = (N[1],), (N[2],) - - divmod_ = pm = (N[2], N[1]), (N[4], N[3]) - - return locals() - -.. code:: ipython2 - - DEFS = defs() - -.. code:: ipython2 - - for name, stack_effect_comment in sorted(DEFS.items()): - print name, '=', doc_from_stack_effect(*stack_effect_comment) - - -.. parsed-literal:: - - ccons = (a1 a2 [.1.] -- [a1 a2 .1.]) - cons = (a1 [.1.] -- [a1 .1.]) - divmod_ = (n2 n1 -- n4 n3) - dup = (a1 -- a1 a1) - dupd = (a2 a1 -- a2 a2 a1) - first = ([a1 .1.] -- a1) - mul = (n1 n2 -- n3) - over = (a2 a1 -- a2 a1 a2) - pm = (n2 n1 -- n4 n3) - pop = (a1 --) - popd = (a2 a1 -- a1) - popdd = (a3 a2 a1 -- a2 a1) - popop = (a2 a1 --) - pred = (n1 -- n2) - rest = ([a1 .1.] -- [.1.]) - rolldown = (a1 a2 a3 -- a2 a3 a1) - rollup = (a1 a2 a3 -- a3 a1 a2) - rrest = ([a1 a2 .1.] -- [.1.]) - second = ([a1 a2 .1.] -- a2) - sqrt = (n1 -- n2) - succ = (n1 -- n2) - swap = (a1 a2 -- a2 a1) - swons = ([.1.] a1 -- [a1 .1.]) - third = ([a1 a2 a3 .1.] -- a3) - tuck = (a2 a1 -- a1 a2 a1) - uncons = ([a1 .1.] -- a1 [.1.]) - - -.. code:: ipython2 - - globals().update(DEFS) - -Compose ``dup`` and ``mul`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. code:: ipython2 - - C(dup, mul) - - - - -.. parsed-literal:: - - ((n1,), (n2,)) - - - -Revisit the ``F`` function, works fine. - -.. code:: ipython2 - - F = reduce(C, (pop, swap, rolldown, rest, rest, cons, cons)) - F - - - - -.. parsed-literal:: - - (((a1, (a2, s1)), a3, a4, a5), ((a4, (a3, s1)),)) - - - -.. code:: ipython2 - - print doc_from_stack_effect(*F) - - -.. parsed-literal:: - - ([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.]) - - -Some otherwise inefficient functions are no longer to be feared. We can -also get the effect of combinators in some limited cases. - -.. code:: ipython2 - - def neato(*funcs): - print doc_from_stack_effect(*reduce(C, funcs)) - -.. code:: ipython2 - - # e.g. [swap] dip - neato(rollup, swap, rolldown) - - -.. parsed-literal:: - - (a1 a2 a3 -- a2 a1 a3) - - -.. code:: ipython2 - - # e.g. [popop] dipd - neato(popdd, rolldown, pop) - - -.. parsed-literal:: - - (a1 a2 a3 a4 -- a3 a4) - - -.. code:: ipython2 - - # Reverse the order of the top three items. - neato(rollup, swap) - - -.. parsed-literal:: - - (a1 a2 a3 -- a3 a2 a1) - - -``compile_()`` version 2 -^^^^^^^^^^^^^^^^^^^^^^^^ - -Because the type labels represent themselves as valid Python identifiers -the ``compile_()`` function doesn’t need to generate them anymore: - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - print compile_('F', F) - - -.. parsed-literal:: - - def F(stack): - """([a1 a2 .1.] a3 a4 a5 -- [a4 a3 .1.])""" - (a5, (a4, (a3, ((a1, (a2, s1)), stack)))) = stack - return ((a4, (a3, s1)), stack) - - -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 - - print compile_('sqr', C(dup, mul)) - - -.. parsed-literal:: - - def sqr(stack): - """(n1 -- n2)""" - (n1, stack) = stack - return (n2, stack) - - -(Eventually I should come back around to this becuase it’s not tooo -difficult to exend this code to be able to compile e.g. -``n2 = mul(n1, n1)`` for ``mul`` with the right variable names and -insert it in the right place. It requires a little more support from the -library functions, in that we need to know to call ``mul()`` the Python -function for ``mul`` the Joy function, but since *most* of the math -functions (at least) are already wrappers it should be straightforward.) - -``compilable()`` -^^^^^^^^^^^^^^^^ - -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 - - from itertools import imap - - - def compilable(f): - return isinstance(f, tuple) and all(imap(compilable, f)) or stacky(f) - -.. code:: ipython2 - - for name, stack_effect_comment in sorted(defs().items()): - if compilable(stack_effect_comment): - print name, '=', doc_from_stack_effect(*stack_effect_comment) - - -.. parsed-literal:: - - ccons = (a1 a2 [.1.] -- [a1 a2 .1.]) - cons = (a1 [.1.] -- [a1 .1.]) - dup = (a1 -- a1 a1) - dupd = (a2 a1 -- a2 a2 a1) - first = ([a1 .1.] -- a1) - over = (a2 a1 -- a2 a1 a2) - pop = (a1 --) - popd = (a2 a1 -- a1) - popdd = (a3 a2 a1 -- a2 a1) - popop = (a2 a1 --) - rest = ([a1 .1.] -- [.1.]) - rolldown = (a1 a2 a3 -- a2 a3 a1) - rollup = (a1 a2 a3 -- a3 a1 a2) - rrest = ([a1 a2 .1.] -- [.1.]) - second = ([a1 a2 .1.] -- a2) - swap = (a1 a2 -- a2 a1) - swons = ([.1.] a1 -- [a1 .1.]) - third = ([a1 a2 a3 .1.] -- a3) - tuck = (a2 a1 -- a1 a2 a1) - uncons = ([a1 .1.] -- a1 [.1.]) - - -Part V: Functions that use the Stack ------------------------------------- - -Consider the ``stack`` function which grabs the whole stack, quotes it, -and puts it on itself: - -:: - - stack (... -- ... [...] ) - stack (... a -- ... a [a ...] ) - stack (... b a -- ... b a [a b ...]) - -We would like to represent this in Python somehow. To do this we use a -simple, elegant trick. - -:: - - stack S -- ( S, S) - stack (a, S) -- ( (a, S), (a, S)) - stack (a, (b, S)) -- ( (a, (b, S)), (a, (b, S))) - -Instead of representing the stack effect comments as a single tuple -(with N items in it) we use the same cons-list structure to hold the -sequence and ``unify()`` the whole comments. - -``stack∘uncons`` -~~~~~~~~~~~~~~~~ - -Let’s try composing ``stack`` and ``uncons``. We want this result: - -:: - - stack∘uncons (... a -- ... a a [...]) - -The stack effects are: - -:: - - stack = S -- (S, S) - - uncons = ((a, Z), S) -- (Z, (a, S)) - -Unifying: - -:: - - S -- (S, S) ∘ ((a, Z), S) -- (Z, (a, S )) - w/ { S: (a, Z) } - (a, Z) -- ∘ -- (Z, (a, (a, Z))) - -So: - -:: - - stack∘uncons == (a, Z) -- (Z, (a, (a, Z))) - -It works. - -``stack∘uncons∘uncons`` -~~~~~~~~~~~~~~~~~~~~~~~ - -Let’s try ``stack∘uncons∘uncons``: - -:: - - (a, S ) -- (S, (a, (a, S ))) ∘ ((b, Z), S` ) -- (Z, (b, S` )) - - w/ { S: (b, Z) } - - (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), S` ) -- (Z, (b, S` )) - - w/ { S`: (a, (a, (b, Z))) } - - (a, (b, Z)) -- ((b, Z), (a, (a, (b, Z)))) ∘ ((b, Z), (a, (a, (b, Z)))) -- (Z, (b, (a, (a, (b, Z))))) - - (a, (b, Z)) -- (Z, (b, (a, (a, (b, Z))))) - -It works. - -``compose()`` version 2 -^^^^^^^^^^^^^^^^^^^^^^^ - -This function has to be modified to use the new datastructures and it is -no longer recursive, instead recursion happens as part of unification. -Further, the first and second of Pöial’s rules are now handled -automatically by the unification algorithm. (One easy way to see this is -that now an empty stack effect comment is represented by a -``StackJoyType`` instance which is not “falsey” and so neither of the -first two rules’ ``if`` clauses will ever be ``True``. Later on I change -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 - - 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. - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - C(stack, uncons) - - - - -.. parsed-literal:: - - ((a1, s1), (s1, (a1, (a1, s1)))) - - - -.. code:: ipython2 - - reduce(C, (stack, uncons, uncons)) - - - - -.. parsed-literal:: - - ((a1, (a2, s1)), (s1, (a2, (a1, (a1, (a2, s1)))))) - - - -The display function should be changed too. - -``doc_from_stack_effect()`` version 2 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Clunky junk, but it will suffice for now. - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - for name, stack_effect_comment in sorted(NEW_DEFS.items()): - print name, '=', doc_from_stack_effect(*stack_effect_comment) - - -.. parsed-literal:: - - ccons = (a1 a2 [.1.] -- [a1 a2 .1.]) - cons = (a1 [.1.] -- [a1 .1.]) - divmod_ = (n2 n1 -- n4 n3) - dup = (a1 -- a1 a1) - dupd = (a2 a1 -- a2 a2 a1) - first = ([a1 .1.] -- a1) - mul = (n1 n2 -- n3) - over = (a2 a1 -- a2 a1 a2) - pm = (n2 n1 -- n4 n3) - pop = (a1 --) - popd = (a2 a1 -- a1) - popdd = (a3 a2 a1 -- a2 a1) - popop = (a2 a1 --) - pred = (n1 -- n2) - rest = ([a1 .1.] -- [.1.]) - rolldown = (a1 a2 a3 -- a2 a3 a1) - rollup = (a1 a2 a3 -- a3 a1 a2) - rrest = ([a1 a2 .1.] -- [.1.]) - second = ([a1 a2 .1.] -- a2) - sqrt = (n1 -- n2) - stack = (... -- ... [...]) - succ = (n1 -- n2) - swaack = ([.1.] -- [.0.]) - swap = (a1 a2 -- a2 a1) - swons = ([.1.] a1 -- [a1 .1.]) - third = ([a1 a2 a3 .1.] -- a3) - tuck = (a2 a1 -- a1 a2 a1) - uncons = ([a1 .1.] -- a1 [.1.]) - - -.. code:: ipython2 - - 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))) - - -.. parsed-literal:: - - - (... -- ... [...]) - - (... a1 -- ... a1 a1 [...]) - - (... a2 a1 -- ... a2 a1 a1 a2 [...]) - - (... a1 -- ... a1 [a1 ...]) - - -.. code:: ipython2 - - print doc_from_stack_effect(*C(ccons, stack)) - - -.. parsed-literal:: - - (... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...]) - - -.. code:: ipython2 - - Q = C(ccons, stack) - - Q - - - - -.. parsed-literal:: - - ((s1, (a1, (a2, s2))), (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2))) - - - -``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: - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - print compile_('Q', Q) - - -.. parsed-literal:: - - def Q(stack): - """(... a2 a1 [.1.] -- ... [a2 a1 .1.] [[a2 a1 .1.] ...])""" - (s1, (a1, (a2, s2))) = stack - return (((a2, (a1, s1)), s2), ((a2, (a1, s1)), s2)) - - - - - - - -.. code:: ipython2 - - unstack = (S[1], S[0]), S[1] - enstacken = S[0], (S[0], S[1]) - -.. code:: ipython2 - - print doc_from_stack_effect(*unstack) - - -.. parsed-literal:: - - ([.1.] --) - - -.. code:: ipython2 - - print doc_from_stack_effect(*enstacken) - - -.. parsed-literal:: - - (-- [.0.]) - - -.. code:: ipython2 - - print doc_from_stack_effect(*C(cons, unstack)) - - -.. parsed-literal:: - - (a1 [.1.] -- a1) - - -.. code:: ipython2 - - print doc_from_stack_effect(*C(cons, enstacken)) - - -.. parsed-literal:: - - (a1 [.1.] -- [[a1 .1.] .2.]) - - -.. code:: ipython2 - - C(cons, unstack) - - - - -.. parsed-literal:: - - ((s1, (a1, s2)), (a1, s1)) - - - - -Part VI: Multiple Stack Effects -------------------------------- - -… - -.. code:: ipython2 - - class IntJoyType(NumberJoyType): prefix = 'i' - - - F = map(FloatJoyType, _R) - I = map(IntJoyType, _R) - -.. code:: ipython2 - - 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])), - ] - -.. code:: ipython2 - - for f in muls: - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (i1 i2 -- i3) - (i1 f2 -- f3) - (f1 i2 -- f3) - (f1 f2 -- f3) - - -.. code:: ipython2 - - 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) - - -.. parsed-literal:: - - (a1 -- a1 a1) (i1 i2 -- i3) (i1 -- i2) - (a1 -- a1 a1) (f1 f2 -- f3) (f1 -- f2) - - -.. code:: ipython2 - - 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 MC(F, G): - return sorted(set(meta_compose(F, G))) - -.. code:: ipython2 - - for f in MC([dup], [mul]): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (n1 -- n2) - - -.. code:: ipython2 - - for f in MC([dup], muls): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (f1 -- f2) - (i1 -- i2) - - -Representing an Unbounded Sequence of Types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -We can borrow a trick from `Brzozowski’s Derivatives of Regular -Expressions `__ to -invent a new type of type variable, a “sequence type” (I think this is -what they mean in the literature by that term…) or “`Kleene -Star `__” type. I’m going to -represent it as a type letter and the asterix, so a sequence of zero or -more ``AnyJoyType`` variables would be: - -:: - - A* - -The ``A*`` works by splitting the universe into two alternate histories: - -:: - - A* -> 0 | A A* - -The Kleene star variable disappears in one universe, and in the other it -turns into an ``AnyJoyType`` variable followed by itself again. We have -to return all universes (represented by their substitution dicts, the -“unifiers”) that don’t lead to type conflicts. - -Consider unifying two stacks (the lowercase letters are any type -variables of the kinds we have defined so far): - -:: - - [a A* b .0.] U [c d .1.] - w/ {c: a} - [ A* b .0.] U [ d .1.] - -Now we have to split universes to unify ``A*``. In the first universe it -disappears: - -:: - - [b .0.] U [d .1.] - w/ {d: b, .1.: .0.} - [] U [] - -While in the second it spawns an ``A``, which we will label ``e``: - -:: - - [e A* b .0.] U [d .1.] - w/ {d: e} - [ A* b .0.] U [ .1.] - w/ {.1.: A* b .0.} - [ A* b .0.] U [ A* b .0.] - -Giving us two unifiers: - -:: - - {c: a, d: b, .1.: .0.} - {c: a, d: e, .1.: A* b .0.} - -.. code:: ipython2 - - class KleeneStar(object): - - kind = AnyJoyType - - 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 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 __ge__(self, other): - return self.kind >= other.kind - - def __add__(self, other): - return self.__class__(self.number + other) - __radd__ = __add__ - - 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 - - - As = map(AnyStarJoyType, _R) - Ns = map(NumberStarJoyType, _R) - Ss = map(StackStarJoyType, _R) - -``unify()`` version 4 -^^^^^^^^^^^^^^^^^^^^^ - -Can now return multiple results… - -.. code:: ipython2 - - 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} - -.. code:: ipython2 - - a = (As[1], S[1]) - a - - - - -.. parsed-literal:: - - (a1*, s1) - - - -.. code:: ipython2 - - b = (A[1], S[2]) - b - - - - -.. parsed-literal:: - - (a1, s2) - - - -.. code:: ipython2 - - for result in unify(b, a): - print result, '->', update(result, a), update(result, b) - - -.. parsed-literal:: - - {s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2) - {a1: a10001, s2: (a1*, s1)} -> (a1*, s1) (a10001, (a1*, s1)) - - -.. code:: ipython2 - - for result in unify(a, b): - print result, '->', update(result, a), update(result, b) - - -.. parsed-literal:: - - {s1: (a1, s2)} -> (a1*, (a1, s2)) (a1, s2) - {a1: a10002, s2: (a1*, s1)} -> (a1*, s1) (a10002, (a1*, s1)) - - -:: - - (a1*, s1) [a1*] (a1, s2) [a1] - - (a1*, (a1, s2)) [a1* a1] (a1, s2) [a1] - - (a1*, s1) [a1*] (a2, (a1*, s1)) [a2 a1*] - -.. code:: ipython2 - - sum_ = ((Ns[1], S[1]), S[0]), (N[0], S[0]) - - print doc_from_stack_effect(*sum_) - - -.. parsed-literal:: - - ([n1* .1.] -- n0) - - -.. code:: ipython2 - - f = (N[1], (N[2], (N[3], S[1]))), S[0] - - print doc_from_stack_effect(S[0], f) - - -.. parsed-literal:: - - (-- [n1 n2 n3 .1.]) - - -.. code:: ipython2 - - for result in unify(sum_[0], f): - print result, '->', update(result, sum_[1]) - - -.. parsed-literal:: - - {s1: (n1, (n2, (n3, s1)))} -> (n0, s0) - {n1: n10001, s1: (n2, (n3, s1))} -> (n0, s0) - {n1: n10001, s1: (n3, s1), n2: n10002} -> (n0, s0) - {n1: n10001, s1: (n1*, s1), n3: n10003, n2: n10002} -> (n0, s0) - - -``compose()`` version 3 -^^^^^^^^^^^^^^^^^^^^^^^ - -This function has to be modified to yield multiple results. - -.. code:: ipython2 - - 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)) - - - -.. code:: ipython2 - - 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) - -.. code:: ipython2 - - for f in MC([dup], muls): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (f1 -- f2) - (i1 -- i2) - - -.. code:: ipython2 - - - - for f in MC([dup], [sum_]): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - ([n1* .1.] -- [n1* .1.] n1) - - -.. code:: ipython2 - - - - for f in MC([cons], [sum_]): - print doc_from_stack_effect(*f) - - -.. parsed-literal:: - - (a1 [.1.] -- n1) - (n1 [n1* .1.] -- n2) - - -.. code:: ipython2 - - 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) - - -.. parsed-literal:: - - (a1 [.1.] -- [a1 .1.]) ([n1 n1* .1.] -- n0) (n1 [n1* .1.] -- n2) - - -.. code:: ipython2 - - a = (A[4], (As[1], (A[3], S[1]))) - a - - - - -.. parsed-literal:: - - (a4, (a1*, (a3, s1))) - - - -.. code:: ipython2 - - b = (A[1], (A[2], S[2])) - b - - - - -.. parsed-literal:: - - (a1, (a2, s2)) - - - -.. code:: ipython2 - - for result in unify(b, a): - print result - - -.. parsed-literal:: - - {a1: a4, s2: s1, a2: a3} - {a1: a4, s2: (a1*, (a3, s1)), a2: a10003} - - -.. code:: ipython2 - - for result in unify(a, b): - print result - - -.. parsed-literal:: - - {s2: s1, a2: a3, a4: a1} - {s2: (a1*, (a3, s1)), a2: a10004, a4: a1} - - -Part VII: Typing Combinators ----------------------------- - -In order to compute the stack effect of combinators you kinda have to -have the quoted programs they expect available. In the most general -case, the ``i`` combinator, you can’t say anything about its stack -effect other than it expects one quote: - -:: - - i (... [.1.] -- ... .1.) - -Or - -:: - - i (... [A* .1.] -- ... A*) - -Consider the type of: - -:: - - [cons] dip - -Obviously it would be: - -:: - - (a1 [..1] a2 -- [a1 ..1] a2) - -``dip`` itself could have: - -:: - - (a1 [..1] -- ... then what? - -Without any information about the contents of the quote we can’t say -much about the result. - -Hybrid Inferencer/Interpreter -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -I think there’s a way forward. If we convert our list (of terms we are -composing) into a stack structure we can use it as a *Joy expression*, -then we can treat the *output half* of a function’s stack effect comment -as a Joy interpreter stack, and just execute combinators directly. We -can hybridize the compostition function with an interpreter to evaluate -combinators, compose non-combinator functions, and put type variables on -the stack. For combinators like ``branch`` that can have more than one -stack effect we have to “split universes” again and return both. - -Joy Types for Functions -^^^^^^^^^^^^^^^^^^^^^^^ - -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 - - class FunctionJoyType(AnyJoyType): - - 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 __repr__(self): - return self.name - -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 - - class SymbolJoyType(FunctionJoyType): - prefix = 'F' - -For combinators the list contains Python functions. - -.. code:: ipython2 - - class CombinatorJoyType(FunctionJoyType): - - prefix = 'C' - - 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] - -For simple combinators that have only one effect (like ``dip``) you only -need one function and it can be the combinator itself. - -.. code:: ipython2 - - import joy.library - - 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. - -.. code:: ipython2 - - 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 - - branch = CombinatorJoyType('branch', [branch_true, branch_false], 100) - -You can also provide an optional stack effect, input-side only, that -will then be used as an identity function (that accepts and returns -stacks that match the “guard” stack effect) which will be used to guard -against type mismatches going into the evaluation of the combinator. - -``infer()`` -^^^^^^^^^^^ - -With those in place, we can define a function that accepts a sequence of -Joy type variables, including ones representing functions (not just -values), and attempts to grind out all the possible stack effects of -that expression. - -One tricky thing is that type variables *in the expression* have to be -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 - - ID = S[0], S[0] # Identity function. - - - 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] - - 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) - - 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) - - else: - fi, fo = F - res = _infer(e, (fi, (n, fo))) - - 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 _log_it(e, F): - _log.info( - u'%3i %s ∘ %s', - len(inspect_stack()), - doc_from_stack_effect(*F), - expression_to_string(e), - ) - -Work in Progress -^^^^^^^^^^^^^^^^ - -And that brings us to current Work-In-Progress. The mixed-mode -inferencer/interpreter ``infer()`` function seems to work well. There -are details I should document, and the rest of the code in the ``types`` -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 : - -.. code:: ipython2 - - 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) - - globals().update(FUNCTIONS) - - h = infer((pred, s2), (mul, s3), (div, s4), (nullary, (bool, s5)), dipd, branch) - - print '-' * 40 - - for fi, fo in h: - print doc_from_stack_effect(fi, fo) - - -:: - - - --------------------------------------------------------------------------- - - ZeroDivisionError Traceback (most recent call last) - - in () - ----> 1 1/0 # (Don't try to run this cell! It's not going to work. This is "read only" code heh..) - 2 - 3 logging.basicConfig(format='%(message)s', stream=sys.stdout, level=logging.INFO) - 4 - 5 globals().update(FUNCTIONS) - - - ZeroDivisionError: integer division or modulo by zero - - -The numbers at the start of the lines are the current depth of the -Python call stack. They’re followed by the current computed stack effect -(initialized to ``ID``) then the pending expression (the inference of -the stack effect of which is the whole object of the current example.) - -In this example we are implementing (and inferring) ``ifte`` as -``[nullary bool] dipd branch`` which shows off a lot of the current -implementation in action. - -:: - - 7 (--) ∘ [pred] [mul] [div] [nullary bool] dipd branch - 8 (-- [pred ...2]) ∘ [mul] [div] [nullary bool] dipd branch - 9 (-- [pred ...2] [mul ...3]) ∘ [div] [nullary bool] dipd branch - 10 (-- [pred ...2] [mul ...3] [div ...4]) ∘ [nullary bool] dipd branch - 11 (-- [pred ...2] [mul ...3] [div ...4] [nullary bool ...5]) ∘ dipd branch - 15 (-- [pred ...5]) ∘ nullary bool [mul] [div] branch - 19 (-- [pred ...2]) ∘ [stack] dinfrirst bool [mul] [div] branch - 20 (-- [pred ...2] [stack ]) ∘ dinfrirst bool [mul] [div] branch - 22 (-- [pred ...2] [stack ]) ∘ dip infra first bool [mul] [div] branch - 26 (--) ∘ stack [pred] infra first bool [mul] [div] branch - 29 (... -- ... [...]) ∘ [pred] infra first bool [mul] [div] branch - 30 (... -- ... [...] [pred ...1]) ∘ infra first bool [mul] [div] branch - 34 (--) ∘ pred s1 swaack first bool [mul] [div] branch - 37 (n1 -- n2) ∘ [n1] swaack first bool [mul] [div] branch - 38 (... n1 -- ... n2 [n1 ...]) ∘ swaack first bool [mul] [div] branch - 41 (... n1 -- ... n1 [n2 ...]) ∘ first bool [mul] [div] branch - 44 (n1 -- n1 n2) ∘ bool [mul] [div] branch - 47 (n1 -- n1 b1) ∘ [mul] [div] branch - 48 (n1 -- n1 b1 [mul ...1]) ∘ [div] branch - 49 (n1 -- n1 b1 [mul ...1] [div ...2]) ∘ branch - 53 (n1 -- n1) ∘ div - 56 (f2 f1 -- f3) ∘ - 56 (i1 f1 -- f2) ∘ - 56 (f1 i1 -- f2) ∘ - 56 (i2 i1 -- f1) ∘ - 53 (n1 -- n1) ∘ mul - 56 (f2 f1 -- f3) ∘ - 56 (i1 f1 -- f2) ∘ - 56 (f1 i1 -- f2) ∘ - 56 (i2 i1 -- i3) ∘ - ---------------------------------------- - (f2 f1 -- f3) - (i1 f1 -- f2) - (f1 i1 -- f2) - (i2 i1 -- f1) - (i2 i1 -- i3) - -Conclusion ----------- - -We built a simple type inferencer, and a kind of crude “compiler” for a -subset of Joy functions. Then we built a more powerful inferencer that -actually does some evaluation and explores branching code paths - -Work remains to be done: - -- the rest of the library has to be covered -- figure out how to deal with ``loop`` and ``genrec``, etc.. -- extend the types to check values (see the appendix) -- other kinds of “higher order” type variables, OR, AND, etc.. -- maybe rewrite in Prolog for great good? -- definitions - - - don’t permit composition of functions that don’t compose - - auto-compile compilable functions - -- Compiling more than just the Yin functions. -- getting better visibility (than Python debugger.) -- DOOOOCS!!!! Lots of docs! - - - docstrings all around - - improve this notebook (it kinda falls apart at the end - narratively. I went off and just started writing code to see if it - would work. It does, but now I have to come back and describe here - what I did. - -Appendix: Joy in the Logical Paradigm -------------------------------------- - -For *type checking* to work the type label classes have to be modified -to let ``T >= t`` succeed, where e.g. ``T`` is ``IntJoyType`` and ``t`` -is ``int``. If you do that you can take advantage of the *logical -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. - -.. code:: ipython2 - - 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/notebooks/Zipper.rst b/docs/sphinx_docs/notebooks/Zipper.rst deleted file mode 100644 index dc4f996..0000000 --- a/docs/sphinx_docs/notebooks/Zipper.rst +++ /dev/null @@ -1,352 +0,0 @@ -Traversing Datastructures with Zippers -====================================== - -This notebook is about using the “zipper” with joy datastructures. See -the `Zipper wikipedia -entry `__ or -the original paper: `“FUNCTIONAL PEARL The Zipper” by Gérard -Huet `__ - -Given a datastructure on the stack we can navigate through it, modify -it, and rebuild it using the “zipper” technique. - -.. code:: ipython2 - - from notebook_preamble import J, V, define - -Trees ------ - -In Joypy there aren’t any complex datastructures, just ints, floats, -strings, Symbols (strings that are names of functions) and sequences -(aka lists, aka quoted literals, aka aggregates, etc…), but we can build -`trees `__ out -of sequences. - -.. code:: ipython2 - - J('[1 [2 [3 4 25 6] 7] 8]') - - -.. parsed-literal:: - - [1 [2 [3 4 25 6] 7] 8] - - -Zipper in Joy -------------- - -Zippers work by keeping track of the current item, the already-seen -items, and the yet-to-be seen items as you traverse a datastructure (the -datastructure used to keep track of these items is the zipper.) - -In Joy we can do this with the following words: - -:: - - z-down == [] swap uncons swap - z-up == swons swap shunt - z-right == [swons] cons dip uncons swap - z-left == swons [uncons swap] dip swap - -Let’s use them to change 25 into 625. The first time a word is used I -show the trace so you can see how it works. If we were going to use -these a lot it would make sense to write Python versions for efficiency, -but see below. - -.. code:: ipython2 - - define('z-down == [] swap uncons swap') - define('z-up == swons swap shunt') - define('z-right == [swons] cons dip uncons swap') - define('z-left == swons [uncons swap] dip swap') - -.. code:: ipython2 - - V('[1 [2 [3 4 25 6] 7] 8] z-down') - - -.. parsed-literal:: - - . [1 [2 [3 4 25 6] 7] 8] z-down - [1 [2 [3 4 25 6] 7] 8] . z-down - [1 [2 [3 4 25 6] 7] 8] . [] swap uncons swap - [1 [2 [3 4 25 6] 7] 8] [] . swap uncons swap - [] [1 [2 [3 4 25 6] 7] 8] . uncons swap - [] 1 [[2 [3 4 25 6] 7] 8] . swap - [] [[2 [3 4 25 6] 7] 8] 1 . - - -.. code:: ipython2 - - V('[] [[2 [3 4 25 6] 7] 8] 1 z-right') - - -.. parsed-literal:: - - . [] [[2 [3 4 25 6] 7] 8] 1 z-right - [] . [[2 [3 4 25 6] 7] 8] 1 z-right - [] [[2 [3 4 25 6] 7] 8] . 1 z-right - [] [[2 [3 4 25 6] 7] 8] 1 . z-right - [] [[2 [3 4 25 6] 7] 8] 1 . [swons] cons dip uncons swap - [] [[2 [3 4 25 6] 7] 8] 1 [swons] . cons dip uncons swap - [] [[2 [3 4 25 6] 7] 8] [1 swons] . dip uncons swap - [] . 1 swons [[2 [3 4 25 6] 7] 8] uncons swap - [] 1 . swons [[2 [3 4 25 6] 7] 8] uncons swap - [] 1 . swap cons [[2 [3 4 25 6] 7] 8] uncons swap - 1 [] . cons [[2 [3 4 25 6] 7] 8] uncons swap - [1] . [[2 [3 4 25 6] 7] 8] uncons swap - [1] [[2 [3 4 25 6] 7] 8] . uncons swap - [1] [2 [3 4 25 6] 7] [8] . swap - [1] [8] [2 [3 4 25 6] 7] . - - -.. code:: ipython2 - - J('[1] [8] [2 [3 4 25 6] 7] z-down') - - -.. parsed-literal:: - - [1] [8] [] [[3 4 25 6] 7] 2 - - -.. code:: ipython2 - - J('[1] [8] [] [[3 4 25 6] 7] 2 z-right') - - -.. parsed-literal:: - - [1] [8] [2] [7] [3 4 25 6] - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [3 4 25 6] z-down') - - -.. parsed-literal:: - - [1] [8] [2] [7] [] [4 25 6] 3 - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [] [4 25 6] 3 z-right') - - -.. parsed-literal:: - - [1] [8] [2] [7] [3] [25 6] 4 - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [3] [25 6] 4 z-right') - - -.. parsed-literal:: - - [1] [8] [2] [7] [4 3] [6] 25 - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [4 3] [6] 25 sqr') - - -.. parsed-literal:: - - [1] [8] [2] [7] [4 3] [6] 625 - - -.. code:: ipython2 - - V('[1] [8] [2] [7] [4 3] [6] 625 z-up') - - -.. parsed-literal:: - - . [1] [8] [2] [7] [4 3] [6] 625 z-up - [1] . [8] [2] [7] [4 3] [6] 625 z-up - [1] [8] . [2] [7] [4 3] [6] 625 z-up - [1] [8] [2] . [7] [4 3] [6] 625 z-up - [1] [8] [2] [7] . [4 3] [6] 625 z-up - [1] [8] [2] [7] [4 3] . [6] 625 z-up - [1] [8] [2] [7] [4 3] [6] . 625 z-up - [1] [8] [2] [7] [4 3] [6] 625 . z-up - [1] [8] [2] [7] [4 3] [6] 625 . swons swap shunt - [1] [8] [2] [7] [4 3] [6] 625 . swap cons swap shunt - [1] [8] [2] [7] [4 3] 625 [6] . cons swap shunt - [1] [8] [2] [7] [4 3] [625 6] . swap shunt - [1] [8] [2] [7] [625 6] [4 3] . shunt - [1] [8] [2] [7] [3 4 625 6] . - - -.. code:: ipython2 - - J('[1] [8] [2] [7] [3 4 625 6] z-up') - - -.. parsed-literal:: - - [1] [8] [2 [3 4 625 6] 7] - - -.. code:: ipython2 - - J('[1] [8] [2 [3 4 625 6] 7] z-up') - - -.. parsed-literal:: - - [1 [2 [3 4 625 6] 7] 8] - - -``dip`` and ``infra`` ---------------------- - -In Joy we have the ``dip`` and ``infra`` combinators which can “target” -or “address” any particular item in a Joy tree structure. - -.. code:: ipython2 - - V('[1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra') - - -.. parsed-literal:: - - . [1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] infra - [1 [2 [3 4 25 6] 7] 8] . [[[[[[sqr] dipd] infra] dip] infra] dip] infra - [1 [2 [3 4 25 6] 7] 8] [[[[[[sqr] dipd] infra] dip] infra] dip] . infra - 8 [2 [3 4 25 6] 7] 1 . [[[[[sqr] dipd] infra] dip] infra] dip [] swaack - 8 [2 [3 4 25 6] 7] 1 [[[[[sqr] dipd] infra] dip] infra] . dip [] swaack - 8 [2 [3 4 25 6] 7] . [[[[sqr] dipd] infra] dip] infra 1 [] swaack - 8 [2 [3 4 25 6] 7] [[[[sqr] dipd] infra] dip] . infra 1 [] swaack - 7 [3 4 25 6] 2 . [[[sqr] dipd] infra] dip [8] swaack 1 [] swaack - 7 [3 4 25 6] 2 [[[sqr] dipd] infra] . dip [8] swaack 1 [] swaack - 7 [3 4 25 6] . [[sqr] dipd] infra 2 [8] swaack 1 [] swaack - 7 [3 4 25 6] [[sqr] dipd] . infra 2 [8] swaack 1 [] swaack - 6 25 4 3 . [sqr] dipd [7] swaack 2 [8] swaack 1 [] swaack - 6 25 4 3 [sqr] . dipd [7] swaack 2 [8] swaack 1 [] swaack - 6 25 . sqr 4 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 25 . dup mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 25 25 . mul 4 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 625 . 4 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 625 4 . 3 [7] swaack 2 [8] swaack 1 [] swaack - 6 625 4 3 . [7] swaack 2 [8] swaack 1 [] swaack - 6 625 4 3 [7] . swaack 2 [8] swaack 1 [] swaack - 7 [3 4 625 6] . 2 [8] swaack 1 [] swaack - 7 [3 4 625 6] 2 . [8] swaack 1 [] swaack - 7 [3 4 625 6] 2 [8] . swaack 1 [] swaack - 8 [2 [3 4 625 6] 7] . 1 [] swaack - 8 [2 [3 4 625 6] 7] 1 . [] swaack - 8 [2 [3 4 625 6] 7] 1 [] . swaack - [1 [2 [3 4 625 6] 7] 8] . - - -If you read the trace carefully you’ll see that about half of it is the -``dip`` and ``infra`` combinators de-quoting programs and “digging” into -the subject datastructure. Instead of maintaining temporary results on -the stack they are pushed into the pending expression (continuation). -When ``sqr`` has run the rest of the pending expression rebuilds the -datastructure. - -``Z`` ------ - -Imagine a function ``Z`` that accepts a sequence of ``dip`` and -``infra`` combinators, a quoted program ``[Q]``, and a datastructure to -work on. It would effectively execute the quoted program as if it had -been embedded in a nested series of quoted programs, e.g.: - -:: - - [...] [Q] [dip dip infra dip infra dip infra] Z - ------------------------------------------------------------- - [...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra - - -The ``Z`` function isn’t hard to make. - -.. code:: ipython2 - - define('Z == [[] cons cons] step i') - -Here it is in action in a simplified scenario. - -.. code:: ipython2 - - V('1 [2 3 4] Z') - - -.. parsed-literal:: - - . 1 [2 3 4] Z - 1 . [2 3 4] Z - 1 [2 3 4] . Z - 1 [2 3 4] . [[] cons cons] step i - 1 [2 3 4] [[] cons cons] . step i - 1 2 [[] cons cons] . i [3 4] [[] cons cons] step i - 1 2 . [] cons cons [3 4] [[] cons cons] step i - 1 2 [] . cons cons [3 4] [[] cons cons] step i - 1 [2] . cons [3 4] [[] cons cons] step i - [1 2] . [3 4] [[] cons cons] step i - [1 2] [3 4] . [[] cons cons] step i - [1 2] [3 4] [[] cons cons] . step i - [1 2] 3 [[] cons cons] . i [4] [[] cons cons] step i - [1 2] 3 . [] cons cons [4] [[] cons cons] step i - [1 2] 3 [] . cons cons [4] [[] cons cons] step i - [1 2] [3] . cons [4] [[] cons cons] step i - [[1 2] 3] . [4] [[] cons cons] step i - [[1 2] 3] [4] . [[] cons cons] step i - [[1 2] 3] [4] [[] cons cons] . step i - [[1 2] 3] 4 [[] cons cons] . i i - [[1 2] 3] 4 . [] cons cons i - [[1 2] 3] 4 [] . cons cons i - [[1 2] 3] [4] . cons i - [[[1 2] 3] 4] . i - . [[1 2] 3] 4 - [[1 2] 3] . 4 - [[1 2] 3] 4 . - - -And here it is doing the main thing. - -.. code:: ipython2 - - J('[1 [2 [3 4 25 6] 7] 8] [sqr] [dip dip infra dip infra dip infra] Z') - - -.. parsed-literal:: - - [1 [2 [3 4 625 6] 7] 8] - - -Addressing ----------- - -Because we are only using two combinators we could replace the list with -a string made from only two characters. - -:: - - [...] [Q] 'ddididi' Zstr - ------------------------------------------------------------- - [...] [[[[[[[Q] dip] dip] infra] dip] infra] dip] infra - -The string can be considered a name or address for an item in the -subject datastructure. - -Determining the right “path” for an item in a tree. ---------------------------------------------------- - -It’s easy to read off (in reverse) the right sequence of “d” and “i” -from the subject datastructure: - -:: - - [ n [ n [ n n x ... - i d i d i d d Bingo! - diff --git a/docs/sphinx_docs/notebooks/index.rst b/docs/sphinx_docs/notebooks/index.rst deleted file mode 100644 index dbb23a5..0000000 --- a/docs/sphinx_docs/notebooks/index.rst +++ /dev/null @@ -1,27 +0,0 @@ - -Essays about Programming in Joy -=============================== - -These essays are adapted from Jupyter notebooks. I hope to have those hosted somewhere where people can view them "live" and interact with them, possibly on MS Azure. For now, Sphinx does such a great job rendering the HTML that I am copying over some notebooks in ReST format and hand-editing them into these documents. - -.. toctree:: - :glob: - :maxdepth: 2 - - Developing - Quadratic - Replacing - Recursion_Combinators - Ordered_Binary_Trees - Treestep - Generator_Programs - Newton-Raphson - Square_Spiral - Zipper - Types - TypeChecking - NoUpdates - Categorical - The_Four_Operations - Derivatives_of_Regular_Expressions - diff --git a/docs/sphinx_docs/notebooks/omg.svg b/docs/sphinx_docs/notebooks/omg.svg deleted file mode 100644 index a3be69c..0000000 --- a/docs/sphinx_docs/notebooks/omg.svg +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - -finite_state_machine - - -i - - -i - - -i->i - - -0 - - -j - -j - - -i->j - - -1 - - -h - - -h - - -h->i - - -0 - - -h->h - - -1 - - -a - -a - - -b - -b - - -a->b - - -0 - - -c - -c - - -a->c - - -1 - - -b->b - - -0 - - -d - -d - - -b->d - - -1 - - -c->b - - -0 - - -e - -e - - -c->e - - -1 - - -d->b - - -0 - - -f - -f - - -d->f - - -1 - - -e->b - - -0 - - -g - -g - - -e->g - - -1 - - -f->h - - -1 - - -f->b - - -0 - - -g->i - - -0 - - -g->g - - -1 - - -j->i - - -0 - - -j->h - - -1 - - - diff --git a/docs/sphinx_docs/parser.rst b/docs/sphinx_docs/parser.rst deleted file mode 100644 index 2306582..0000000 --- a/docs/sphinx_docs/parser.rst +++ /dev/null @@ -1,20 +0,0 @@ - -Parsing Text into Joy Expressions -================================= - -TODO: example... - - -``joy.parser`` ---------------- - - -.. automodule:: joy.parser - :members: - - -Parser Internals ----------------- - -TODO: Document things like the regular expressions used for tokenizing, and the re.Scanner, etc... - diff --git a/docs/sphinx_docs/pretty.rst b/docs/sphinx_docs/pretty.rst deleted file mode 100644 index 866588c..0000000 --- a/docs/sphinx_docs/pretty.rst +++ /dev/null @@ -1,13 +0,0 @@ - -Tracing Joy Execution -===================== - - -``joy.utils.pretty_print`` --------------------------- - - -.. automodule:: joy.utils.pretty_print - :members: - - diff --git a/docs/sphinx_docs/stack.rst b/docs/sphinx_docs/stack.rst deleted file mode 100644 index a4af099..0000000 --- a/docs/sphinx_docs/stack.rst +++ /dev/null @@ -1,13 +0,0 @@ - -Stack or Quote or Sequence or List... -===================================== - - -``joy.utils.stack`` ----------------------- - - -.. automodule:: joy.utils.stack - :members: - - diff --git a/docs/sphinx_docs/types.rst b/docs/sphinx_docs/types.rst deleted file mode 100644 index 5491f3a..0000000 --- a/docs/sphinx_docs/types.rst +++ /dev/null @@ -1,153 +0,0 @@ - -Type Inference of Joy Expressions -================================= - -UPDATE: May 2020 - I removed the type inference code in `joy.utils.types` -but you can find it in the `v0.4.0` tag here: -https://osdn.net/projects/joypy/scm/hg/Joypy/tags - - -Two kinds of type inference are provided, a simple inferencer that can -handle functions that have a single stack effect (aka "type signature") -and that can generate Python code for a limited subset of those -functions, and a more complex inferencer/interpreter hybrid that can -infer the stack effects of most Joy expressions, including multiple stack -effects, unbounded sequences of values, and combinators (if enough -information is available.) - - -``joy.utils.types`` -------------------- - - -Curently (asterix after name indicates a function that can be -auto-compiled to Python):: - - _Tree_add_Ee = ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) * - _Tree_delete_R0 = ([a2 ...1] a1 -- [a2 ...1] a2 a1 a1) * - _Tree_delete_clear_stuff = (a3 a2 [a1 ...1] -- [...1]) * - _Tree_get_E = ([a3 a4 ...1] a2 a1 -- a4) * - add = (n1 n2 -- n3) - and = (b1 b2 -- b3) - bool = (a1 -- b1) - ccons = (a2 a1 [...1] -- [a2 a1 ...1]) * - cons = (a1 [...0] -- [a1 ...0]) * - div = (n1 n2 -- n3) - divmod = (n2 n1 -- n4 n3) - dup = (a1 -- a1 a1) * - dupd = (a2 a1 -- a2 a2 a1) * - dupdd = (a3 a2 a1 -- a3 a3 a2 a1) * - eq = (n1 n2 -- b1) - first = ([a1 ...1] -- a1) * - first_two = ([a1 a2 ...1] -- a1 a2) * - floordiv = (n1 n2 -- n3) - fourth = ([a1 a2 a3 a4 ...1] -- a4) * - ge = (n1 n2 -- b1) - gt = (n1 n2 -- b1) - le = (n1 n2 -- b1) - lshift = (n1 n2 -- n3) - lt = (n1 n2 -- b1) - modulus = (n1 n2 -- n3) - mul = (n1 n2 -- n3) - ne = (n1 n2 -- b1) - neg = (n1 -- n2) - not = (a1 -- b1) - over = (a2 a1 -- a2 a1 a2) * - pm = (n2 n1 -- n4 n3) - pop = (a1 --) * - popd = (a2 a1 -- a1) * - popdd = (a3 a2 a1 -- a2 a1) * - popop = (a2 a1 --) * - popopd = (a3 a2 a1 -- a1) * - popopdd = (a4 a3 a2 a1 -- a2 a1) * - pow = (n1 n2 -- n3) - pred = (n1 -- n2) - rest = ([a1 ...0] -- [...0]) * - rolldown = (a1 a2 a3 -- a2 a3 a1) * - rollup = (a1 a2 a3 -- a3 a1 a2) * - rrest = ([a1 a2 ...1] -- [...1]) * - rshift = (n1 n2 -- n3) - second = ([a1 a2 ...1] -- a2) * - sqrt = (n1 -- n2) - stack = (... -- ... [...]) * - stuncons = (... a1 -- ... a1 a1 [...]) * - stununcons = (... a2 a1 -- ... a2 a1 a1 a2 [...]) * - sub = (n1 n2 -- n3) - succ = (n1 -- n2) - swaack = ([...1] -- [...0]) * - swap = (a1 a2 -- a2 a1) * - swons = ([...1] a1 -- [a1 ...1]) * - third = ([a1 a2 a3 ...1] -- a3) * - truediv = (n1 n2 -- n3) - tuck = (a2 a1 -- a1 a2 a1) * - uncons = ([a1 ...0] -- a1 [...0]) * - unit = (a1 -- [a1 ]) * - unswons = ([a1 ...1] -- [...1] a1) * - - -Example output of the ``infer()`` function. The first number on each -line is the depth of the Python stack. It goes down when the function -backtracks. The next thing on each line is the currently-computed stack -effect so far. It starts with the empty "identity function" and proceeds -through the expression, which is the rest of each line. The function -acts like an interpreter but instead of executing the terms of the -expression it composes them, but for combinators it *does* execute them, -using the output side of the stack effect as the stack. This seems to -work fine. With proper definitions for the behavior of the combinators -that can have more than one effect (like ``branch`` or ``loop``) the -``infer()`` function seems to be able to handle anything I throw at it so -far. - -:: - - 7 (--) ∘ pop swap rolldown rest rest cons cons - 10 (a1 --) ∘ swap rolldown rest rest cons cons - 13 (a3 a2 a1 -- a2 a3) ∘ rolldown rest rest cons cons - 16 (a4 a3 a2 a1 -- a2 a3 a4) ∘ rest rest cons cons - 19 ([a4 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ rest cons cons - 22 ([a4 a5 ...1] a3 a2 a1 -- a2 a3 [...1]) ∘ cons cons - 25 ([a4 a5 ...1] a3 a2 a1 -- a2 [a3 ...1]) ∘ cons - 28 ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) ∘ - ---------------------------------------- - ([a4 a5 ...1] a3 a2 a1 -- [a2 a3 ...1]) - - -Here's another example (implementing ``ifte``) using some combinators:: - - 7 (--) ∘ [pred] [mul] [div] [nullary bool] dipd branch - 8 (-- [pred ...2]) ∘ [mul] [div] [nullary bool] dipd branch - 9 (-- [pred ...2] [mul ...3]) ∘ [div] [nullary bool] dipd branch - 10 (-- [pred ...2] [mul ...3] [div ...4]) ∘ [nullary bool] dipd branch - 11 (-- [pred ...2] [mul ...3] [div ...4] [nullary bool ...5]) ∘ dipd branch - 15 (-- [pred ...5]) ∘ nullary bool [mul] [div] branch - 19 (-- [pred ...2]) ∘ [stack] dinfrirst bool [mul] [div] branch - 20 (-- [pred ...2] [stack ]) ∘ dinfrirst bool [mul] [div] branch - 22 (-- [pred ...2] [stack ]) ∘ dip infra first bool [mul] [div] branch - 26 (--) ∘ stack [pred] infra first bool [mul] [div] branch - 29 (... -- ... [...]) ∘ [pred] infra first bool [mul] [div] branch - 30 (... -- ... [...] [pred ...1]) ∘ infra first bool [mul] [div] branch - 34 (--) ∘ pred s1 swaack first bool [mul] [div] branch - 37 (n1 -- n2) ∘ [n1] swaack first bool [mul] [div] branch - 38 (... n1 -- ... n2 [n1 ...]) ∘ swaack first bool [mul] [div] branch - 41 (... n1 -- ... n1 [n2 ...]) ∘ first bool [mul] [div] branch - 44 (n1 -- n1 n2) ∘ bool [mul] [div] branch - 47 (n1 -- n1 b1) ∘ [mul] [div] branch - 48 (n1 -- n1 b1 [mul ...1]) ∘ [div] branch - 49 (n1 -- n1 b1 [mul ...1] [div ...2]) ∘ branch - 53 (n1 -- n1) ∘ div - 56 (f2 f1 -- f3) ∘ - 56 (i1 f1 -- f2) ∘ - 56 (f1 i1 -- f2) ∘ - 56 (i2 i1 -- f1) ∘ - 53 (n1 -- n1) ∘ mul - 56 (f2 f1 -- f3) ∘ - 56 (i1 f1 -- f2) ∘ - 56 (f1 i1 -- f2) ∘ - 56 (i2 i1 -- i3) ∘ - ---------------------------------------- - (f2 f1 -- f3) - (i1 f1 -- f2) - (f1 i1 -- f2) - (i2 i1 -- f1) - (i2 i1 -- i3) - diff --git a/docs/yow/AMPERSAND.md b/docs/yow/AMPERSAND.md deleted file mode 100644 index e7f5f30..0000000 --- a/docs/yow/AMPERSAND.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# & - -See [and](#and). - diff --git a/docs/yow/AMPERSAND.rst b/docs/yow/AMPERSAND.rst deleted file mode 100644 index 0e39067..0000000 --- a/docs/yow/AMPERSAND.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -& -^^^ - -Basis Function Combinator - -Same as a & b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/AMPERSAND•AMPERSAND.md b/docs/yow/AMPERSAND•AMPERSAND.md deleted file mode 100644 index dcbfc9d..0000000 --- a/docs/yow/AMPERSAND•AMPERSAND.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# && - -Basis Function Combinator - -nulco \[nullary \[false\]\] dip branch - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/AMPERSAND•AMPERSAND.rst b/docs/yow/AMPERSAND•AMPERSAND.rst deleted file mode 100644 index eb6b17a..0000000 --- a/docs/yow/AMPERSAND•AMPERSAND.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -&& -^^^^ - -Basis Function Combinator - -nulco [nullary [false]] dip branch - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/ASTERISK.md b/docs/yow/ASTERISK.md deleted file mode 100644 index 772b2f4..0000000 --- a/docs/yow/ASTERISK.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# * - -See [mul](#mul). - diff --git a/docs/yow/ASTERISK.rst b/docs/yow/ASTERISK.rst deleted file mode 100644 index e153c66..0000000 --- a/docs/yow/ASTERISK.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -* -^^^ - -Basis Function Combinator - -Same as a * b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/BULLET.md b/docs/yow/BULLET.md deleted file mode 100644 index 1b25b7b..0000000 --- a/docs/yow/BULLET.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# • - -See [id](#id). - diff --git a/docs/yow/BULLET.rst b/docs/yow/BULLET.rst deleted file mode 100644 index 01d9d37..0000000 --- a/docs/yow/BULLET.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -• -^^^ - -Basis Function Combinator - -The identity function. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/CIRCUMFLEX-ACCENT.md b/docs/yow/CIRCUMFLEX-ACCENT.md deleted file mode 100644 index 09dcf47..0000000 --- a/docs/yow/CIRCUMFLEX-ACCENT.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# ^ - -See [xor](#xor). - diff --git a/docs/yow/CIRCUMFLEX-ACCENT.rst b/docs/yow/CIRCUMFLEX-ACCENT.rst deleted file mode 100644 index cf71cb6..0000000 --- a/docs/yow/CIRCUMFLEX-ACCENT.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -^ -^^^ - -Basis Function Combinator - -Same as a ^ b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/EQUALS-SIGN.md b/docs/yow/EQUALS-SIGN.md deleted file mode 100644 index bd59635..0000000 --- a/docs/yow/EQUALS-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# = - -See [eq](#eq). - diff --git a/docs/yow/EQUALS-SIGN.rst b/docs/yow/EQUALS-SIGN.rst deleted file mode 100644 index d27c022..0000000 --- a/docs/yow/EQUALS-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -= -^^^ - -Basis Function Combinator - -Same as a == b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.md b/docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.md deleted file mode 100644 index 8f49e92..0000000 --- a/docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# != - -See [ne](#ne). - diff --git a/docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.rst b/docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.rst deleted file mode 100644 index 6d4dd0b..0000000 --- a/docs/yow/EXCLAMATION-MARK•EQUALS-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -!= -^^^^ - -Basis Function Combinator - -Same as a != b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.md b/docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.md deleted file mode 100644 index f3c8dca..0000000 --- a/docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# !- - -Basis Function Combinator - -0 \>= - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.rst b/docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.rst deleted file mode 100644 index b15fced..0000000 --- a/docs/yow/EXCLAMATION-MARK•HYPHEN-MINUS.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -!- -^^^^ - -Basis Function Combinator - -0 >= - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/GREATER-THAN-SIGN.md b/docs/yow/GREATER-THAN-SIGN.md deleted file mode 100644 index 3cae0f3..0000000 --- a/docs/yow/GREATER-THAN-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# > - -See [gt](#gt). - diff --git a/docs/yow/GREATER-THAN-SIGN.rst b/docs/yow/GREATER-THAN-SIGN.rst deleted file mode 100644 index 433976f..0000000 --- a/docs/yow/GREATER-THAN-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -> -^^^ - -Basis Function Combinator - -Same as a > b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.md b/docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.md deleted file mode 100644 index 61d11db..0000000 --- a/docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# >= - -See [ge](#ge). - diff --git a/docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.rst b/docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.rst deleted file mode 100644 index d71590a..0000000 --- a/docs/yow/GREATER-THAN-SIGN•EQUALS-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - ->= -^^^^ - -Basis Function Combinator - -Same as a >= b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/GREATER-THAN-SIGN•GREATER-THAN-SIGN.md b/docs/yow/GREATER-THAN-SIGN•GREATER-THAN-SIGN.md deleted file mode 100644 index bdf7b37..0000000 --- a/docs/yow/GREATER-THAN-SIGN•GREATER-THAN-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# >> - -See [rshift](#rshift). - diff --git a/docs/yow/GREATER-THAN-SIGN•GREATER-THAN-SIGN.rst b/docs/yow/GREATER-THAN-SIGN•GREATER-THAN-SIGN.rst deleted file mode 100644 index 41e9287..0000000 --- a/docs/yow/GREATER-THAN-SIGN•GREATER-THAN-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - ->> -^^^^ - -Basis Function Combinator - -Same as a >> b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/HYPHEN-MINUS.md b/docs/yow/HYPHEN-MINUS.md deleted file mode 100644 index 69bf02c..0000000 --- a/docs/yow/HYPHEN-MINUS.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# - - -See [sub](#sub). - diff --git a/docs/yow/HYPHEN-MINUS.rst b/docs/yow/HYPHEN-MINUS.rst deleted file mode 100644 index 5ef24ee..0000000 --- a/docs/yow/HYPHEN-MINUS.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -- -^^^ - -Basis Function Combinator - -Same as a - b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.md b/docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.md deleted file mode 100644 index 2cc0cfd..0000000 --- a/docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# -- - -See [pred](#pred). - diff --git a/docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.rst b/docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.rst deleted file mode 100644 index b12282d..0000000 --- a/docs/yow/HYPHEN-MINUS•HYPHEN-MINUS.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - - -- -^^^^ - -Basis Function Combinator - -Decrement TOS. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/LESS-THAN-SIGN.md b/docs/yow/LESS-THAN-SIGN.md deleted file mode 100644 index 55a3de2..0000000 --- a/docs/yow/LESS-THAN-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# < - -See [lt](#lt). - diff --git a/docs/yow/LESS-THAN-SIGN.rst b/docs/yow/LESS-THAN-SIGN.rst deleted file mode 100644 index aae47f9..0000000 --- a/docs/yow/LESS-THAN-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -< -^^^ - -Basis Function Combinator - -Same as a < b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.md b/docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.md deleted file mode 100644 index 828250a..0000000 --- a/docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# <= - -See [le](#le). - diff --git a/docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.rst b/docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.rst deleted file mode 100644 index d3c21a0..0000000 --- a/docs/yow/LESS-THAN-SIGN•EQUALS-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -<= -^^^^ - -Basis Function Combinator - -Same as a <= b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.md b/docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.md deleted file mode 100644 index 40a6613..0000000 --- a/docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# <> - -See [ne](#ne). - diff --git a/docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.rst b/docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.rst deleted file mode 100644 index 4fa0642..0000000 --- a/docs/yow/LESS-THAN-SIGN•GREATER-THAN-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -<> -^^^^ - -Basis Function Combinator - -Same as a != b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md b/docs/yow/LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md deleted file mode 100644 index 7d2e3fc..0000000 --- a/docs/yow/LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# \<{} - -Basis Function Combinator - -\[\] swap - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst b/docs/yow/LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst deleted file mode 100644 index cee0ff9..0000000 --- a/docs/yow/LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -<{} -^^^^^ - -Basis Function Combinator - -[] swap - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.md b/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.md deleted file mode 100644 index 5865734..0000000 --- a/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# << - -See [lshift](#lshift). - diff --git a/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.rst b/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.rst deleted file mode 100644 index 450c357..0000000 --- a/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -<< -^^^^ - -Basis Function Combinator - -Same as a << b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md b/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md deleted file mode 100644 index a9d3033..0000000 --- a/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# \<\<{} - -Basis Function Combinator - -\[\] rollup - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst b/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst deleted file mode 100644 index d39b43f..0000000 --- a/docs/yow/LESS-THAN-SIGN•LESS-THAN-SIGN•LEFT-CURLY-BRACKET•RIGHT-CURLY-BRACKET.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -<<{} -^^^^^^ - -Basis Function Combinator - -[] rollup - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/Makefile b/docs/yow/Makefile deleted file mode 100644 index 46c0f1b..0000000 --- a/docs/yow/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -rsts = $(wildcard *.rst) -mds = $(patsubst %.rst,%.md,$(rsts)) - - -all: $(mds) - -clean: - $(RM) -v $(mds) - -$(mds): %.md : %.rst - #pandoc $< -o $@ - sed -e 's/^#/##/' $@ > ../reference/$@ - -# cp -vf $@ ../reference/ diff --git a/docs/yow/PERCENT-SIGN.md b/docs/yow/PERCENT-SIGN.md deleted file mode 100644 index f008225..0000000 --- a/docs/yow/PERCENT-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# % - -See [mod](#mod). - diff --git a/docs/yow/PERCENT-SIGN.rst b/docs/yow/PERCENT-SIGN.rst deleted file mode 100644 index 528b4f3..0000000 --- a/docs/yow/PERCENT-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -% -^^^ - -Basis Function Combinator - -Same as a % b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/PLUS-SIGN.md b/docs/yow/PLUS-SIGN.md deleted file mode 100644 index 18b909a..0000000 --- a/docs/yow/PLUS-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# + - -See [add](#add). - diff --git a/docs/yow/PLUS-SIGN.rst b/docs/yow/PLUS-SIGN.rst deleted file mode 100644 index 258dc39..0000000 --- a/docs/yow/PLUS-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -+ -^^^ - -Basis Function Combinator - -Same as a + b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/PLUS-SIGN•PLUS-SIGN.md b/docs/yow/PLUS-SIGN•PLUS-SIGN.md deleted file mode 100644 index 0068ba0..0000000 --- a/docs/yow/PLUS-SIGN•PLUS-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# ++ - -See [succ](#succ). - diff --git a/docs/yow/PLUS-SIGN•PLUS-SIGN.rst b/docs/yow/PLUS-SIGN•PLUS-SIGN.rst deleted file mode 100644 index 8bb9321..0000000 --- a/docs/yow/PLUS-SIGN•PLUS-SIGN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -++ -^^^^ - -Basis Function Combinator - -Increment TOS. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/QUESTION-MARK.md b/docs/yow/QUESTION-MARK.md deleted file mode 100644 index 76fee40..0000000 --- a/docs/yow/QUESTION-MARK.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# ? - -Basis Function Combinator - -dup bool - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/QUESTION-MARK.rst b/docs/yow/QUESTION-MARK.rst deleted file mode 100644 index 663d908..0000000 --- a/docs/yow/QUESTION-MARK.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -? -^^^ - -Basis Function Combinator - -dup bool - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/SOLIDUS.md b/docs/yow/SOLIDUS.md deleted file mode 100644 index d4ca64f..0000000 --- a/docs/yow/SOLIDUS.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# / - -See [floordiv](#floordiv). - diff --git a/docs/yow/SOLIDUS.rst b/docs/yow/SOLIDUS.rst deleted file mode 100644 index dd0220f..0000000 --- a/docs/yow/SOLIDUS.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -/ -^^^ - -Basis Function Combinator - -Same as a // b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/SOLIDUS•SOLIDUS.md b/docs/yow/SOLIDUS•SOLIDUS.md deleted file mode 100644 index 1acbeeb..0000000 --- a/docs/yow/SOLIDUS•SOLIDUS.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# // - -See [floordiv](#floordiv). - diff --git a/docs/yow/SOLIDUS•SOLIDUS.rst b/docs/yow/SOLIDUS•SOLIDUS.rst deleted file mode 100644 index f818e5e..0000000 --- a/docs/yow/SOLIDUS•SOLIDUS.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -// -^^^^ - -Basis Function Combinator - -Same as a // b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/SOLIDUS•floor.md b/docs/yow/SOLIDUS•floor.md deleted file mode 100644 index e3c5e38..0000000 --- a/docs/yow/SOLIDUS•floor.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# /floor - -See [floordiv](#floordiv). - diff --git a/docs/yow/SOLIDUS•floor.rst b/docs/yow/SOLIDUS•floor.rst deleted file mode 100644 index 1fa1a0f..0000000 --- a/docs/yow/SOLIDUS•floor.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -/floor -^^^^^^^^ - -Basis Function Combinator - -Same as a // b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/VERTICAL-LINE•VERTICAL-LINE.md b/docs/yow/VERTICAL-LINE•VERTICAL-LINE.md deleted file mode 100644 index 6e809fb..0000000 --- a/docs/yow/VERTICAL-LINE•VERTICAL-LINE.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# \|\| - -Basis Function Combinator - -nulco \[nullary\] dip \[true\] branch - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/VERTICAL-LINE•VERTICAL-LINE.rst b/docs/yow/VERTICAL-LINE•VERTICAL-LINE.rst deleted file mode 100644 index fc5fc51..0000000 --- a/docs/yow/VERTICAL-LINE•VERTICAL-LINE.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -|| -^^^^ - -Basis Function Combinator - -nulco [nullary] dip [true] branch - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/abs.md b/docs/yow/abs.md deleted file mode 100644 index 283f93a..0000000 --- a/docs/yow/abs.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# abs - -Basis Function Combinator - -Return the absolute value of the argument. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/abs.rst b/docs/yow/abs.rst deleted file mode 100644 index e4ce189..0000000 --- a/docs/yow/abs.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -abs -^^^^^ - -Basis Function Combinator - -Return the absolute value of the argument. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/add.md b/docs/yow/add.md deleted file mode 100644 index 9ad35b4..0000000 --- a/docs/yow/add.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# add - -Basis Function Combinator - -Same as a + b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/add.rst b/docs/yow/add.rst deleted file mode 100644 index 04d0ae4..0000000 --- a/docs/yow/add.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -add -^^^^^ - -Basis Function Combinator - -Same as a + b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/aliassess.py b/docs/yow/aliassess.py deleted file mode 100644 index 7d8b386..0000000 --- a/docs/yow/aliassess.py +++ /dev/null @@ -1,148 +0,0 @@ -''' -A brutal little script to convert Markdown files for aliases - -This is a one-off script. - -''' -from pathlib import Path -from string import ascii_letters, digits -from unicodedata import name as uname - -from joy.library import ALIASES - - -okay = set(ascii_letters + digits + '_') - - -def units_of_filename(fn): - unit = '' - for char in fn: - if char not in okay: - if unit: - yield unit - unit = '' - yield uname(char).replace(' ', '-') - else: - unit += char - if unit: - yield unit - - -def safe_filename(fn): - return '•'.join(units_of_filename(fn)) - - -def rewrite(name, alias, from_, to): - TO = Path(to) - assert TO.exists() - FROM = Path(from_) - assert FROM.exists() - FROM.write_text(f'''\ --------------- - -# {alias} - -See [{name}](#{name}). - -''') - -for name, aliases in ALIASES: - if name == 'eh': - continue - for alias in aliases: - print(f'Rewrite {safe_filename(alias)}.md to point to {name}.md') - rewrite(name, alias, f'{safe_filename(alias)}.md', f'{name}.md') - -## -##refdir = Path('../reference') -## -### Initialize the Joy dictionary. -##D = initialize() -##default_defs(D) -## -##words = sorted( -## name -## for name in D -## if not name.startswith('_') -## ) -## -### words = '!- != % & && * + ++ - -- / // /floor < << <<{} <= <> <{} = > >= >> ? ^ _Tree_add_Ee _Tree_delete_R0 _Tree_delete_clear_stuff _Tree_get_E _map0 _map1 _map2 _map? _mape _step0 _step1 _stept _times0 _times1 _timest abs add anamorphism and app1 app2 app3 appN at average b binary bool branch ccccons ccons choice clear cleave clop cmp codi codireco concat cond cons dinfrirst dip dipd dipdd disenstacken div divmod down_to_zero drop dup dupd dupdd dupdip dupdipd enstacken eq first first_two flatten floor floordiv fork fourth gcd gcd2 ge genrec getitem grabN grba gt help hypot i id ifte ii infra infrst inscribe le loop lshift lt make_generator map max min mod modulus mul ne neg not nulco nullary of or over pam pick pm pop popd popdd popop popopd popopdd popopop pow pred primrec product quoted range range_to_zero reco rem remainder remove rest reverse roll< roll> rolldown rollup round rrest rshift run second select sharing shift shunt size sort spiral_next split_at split_list sqr sqrt stack stackd step step_zero stuncons stununcons sub succ sum swaack swap swapd swoncat swons tailrec take ternary third times trace truthy tuck unary uncons unique unit unquoted unswons void warranty while words x xor zip || •'.split() -##done_manually = '''\ -##app1.md -##b.md -##binary.md -##ccons.md -##cons.md -##i.md -##infra.md -##nullary.md -##ternary.md -##unary.md -##uncons.md -##x.md'''.split() -## -##for w in words: -## -## ww = safe_filename(w) -## rst = f'{ww}.rst' -## -## fn = f'{w}.md' -## if fn in done_manually: -## continue -## -#### rf = (refdir / fn) -#### if rf.exists(): -#### print(f'copying existing {fn}') -#### Path(fn).write_bytes(rf.read_bytes()) -#### continue -## -## Path(rst).write_text(f'''\ -##-------------- -## -##{w} -##{'^' * (len(w) + 2)} -## -##Basis Function Combinator -## -##{dedent(D[w].__doc__)} -## -##Gentzen diagram. -## -## -##Definition -##~~~~~~~~~~ -## -##if not basis. -## -## -##Derivation -##~~~~~~~~~~ -## -##if not basis. -## -## -##Source -##~~~~~~~~~~ -## -##if basis -## -## -##Discussion -##~~~~~~~~~~ -## -##Lorem ipsum. -## -## -##Crosslinks -##~~~~~~~~~~ -## -##Lorem ipsum. -## -## -##''', encoding='UTF_8') -## -## -#### ww = w.replace('/', '∕') # U+2215 ∕ DIVISION SLASH -#### Path(rst).touch() -#### print(D[w].__doc__) -## diff --git a/docs/yow/anamorphism.md b/docs/yow/anamorphism.md deleted file mode 100644 index 9c5c7d7..0000000 --- a/docs/yow/anamorphism.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# anamorphism - -Basis Function Combinator - -\[pop \[\]\] swap \[dip swons\] genrec - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/anamorphism.rst b/docs/yow/anamorphism.rst deleted file mode 100644 index e6b9b2d..0000000 --- a/docs/yow/anamorphism.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -anamorphism -^^^^^^^^^^^^^ - -Basis Function Combinator - -[pop []] swap [dip swons] genrec - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/and.md b/docs/yow/and.md deleted file mode 100644 index 50e41e5..0000000 --- a/docs/yow/and.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# and - -Basis Function Combinator - -Same as a & b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/and.rst b/docs/yow/and.rst deleted file mode 100644 index 951ed48..0000000 --- a/docs/yow/and.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -and -^^^^^ - -Basis Function Combinator - -Same as a & b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/app2.md b/docs/yow/app2.md deleted file mode 100644 index c8f8b68..0000000 --- a/docs/yow/app2.md +++ /dev/null @@ -1,34 +0,0 @@ ------------------------------------------------------------------------- - -# app2 - -Basis Function Combinator - -Like app1 with two items. - -: ... y x [Q] . app2 - ----------------------------------- - ... [y ...] [Q] . infra first - [x ...] [Q] infra first - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/app2.rst b/docs/yow/app2.rst deleted file mode 100644 index 159a14b..0000000 --- a/docs/yow/app2.rst +++ /dev/null @@ -1,50 +0,0 @@ --------------- - -app2 -^^^^^^ - -Basis Function Combinator - -Like app1 with two items. - :: - - ... y x [Q] . app2 - ----------------------------------- - ... [y ...] [Q] . infra first - [x ...] [Q] infra first - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/app3.md b/docs/yow/app3.md deleted file mode 100644 index 4ac7bea..0000000 --- a/docs/yow/app3.md +++ /dev/null @@ -1,35 +0,0 @@ ------------------------------------------------------------------------- - -# app3 - -Basis Function Combinator - -Like app1 with three items. - -: ... z y x [Q] . app3 - ----------------------------------- - ... [z ...] [Q] . infra first - [y ...] [Q] infra first - [x ...] [Q] infra first - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/app3.rst b/docs/yow/app3.rst deleted file mode 100644 index 1482f06..0000000 --- a/docs/yow/app3.rst +++ /dev/null @@ -1,51 +0,0 @@ --------------- - -app3 -^^^^^^ - -Basis Function Combinator - -Like app1 with three items. - :: - - ... z y x [Q] . app3 - ----------------------------------- - ... [z ...] [Q] . infra first - [y ...] [Q] infra first - [x ...] [Q] infra first - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/appN.md b/docs/yow/appN.md deleted file mode 100644 index 85f95db..0000000 --- a/docs/yow/appN.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# appN - -Basis Function Combinator - -\[grabN\] codi map disenstacken - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/appN.rst b/docs/yow/appN.rst deleted file mode 100644 index 3b9f724..0000000 --- a/docs/yow/appN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -appN -^^^^^^ - -Basis Function Combinator - -[grabN] codi map disenstacken - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/at.md b/docs/yow/at.md deleted file mode 100644 index b6b9be6..0000000 --- a/docs/yow/at.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# at - -See [getitem](#getitem). - diff --git a/docs/yow/at.rst b/docs/yow/at.rst deleted file mode 100644 index 2f9be8c..0000000 --- a/docs/yow/at.rst +++ /dev/null @@ -1,55 +0,0 @@ --------------- - -at -^^^^ - -Basis Function Combinator - - -:: - - getitem == drop first - -Expects an integer and a quote on the stack and returns the item at the -nth position in the quote counting from 0. -:: - - [a b c d] 0 getitem - ------------------------- - a - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/average.md b/docs/yow/average.md deleted file mode 100644 index c696fa9..0000000 --- a/docs/yow/average.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# average - -Basis Function Combinator - -\[sum\] \[size\] cleave / - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/average.rst b/docs/yow/average.rst deleted file mode 100644 index d364eb2..0000000 --- a/docs/yow/average.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -average -^^^^^^^^^ - -Basis Function Combinator - -[sum] [size] cleave / - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/bool.md b/docs/yow/bool.md deleted file mode 100644 index c4ba47a..0000000 --- a/docs/yow/bool.md +++ /dev/null @@ -1,33 +0,0 @@ ------------------------------------------------------------------------- - -# bool - -Basis Function Combinator - -bool(x) -\> bool - -Returns True when the argument x is true, False otherwise. The builtins -True and False are the only two instances of the class bool. The class -bool is a subclass of the class int, and cannot be subclassed. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/bool.rst b/docs/yow/bool.rst deleted file mode 100644 index 12ddbd4..0000000 --- a/docs/yow/bool.rst +++ /dev/null @@ -1,46 +0,0 @@ --------------- - -bool -^^^^^^ - -Basis Function Combinator - -bool(x) -> bool - -Returns True when the argument x is true, False otherwise. -The builtins True and False are the only two instances of the class bool. -The class bool is a subclass of the class int, and cannot be subclassed. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/branch.md b/docs/yow/branch.md deleted file mode 100644 index 9b0888a..0000000 --- a/docs/yow/branch.md +++ /dev/null @@ -1,39 +0,0 @@ ------------------------------------------------------------------------- - -# branch - -Basis Function Combinator - -Use a Boolean value to select one of two quoted programs to run. - - branch == roll< choice i - - False [F] [T] branch - -------------------------- - F - - True [F] [T] branch - ------------------------- - T - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/branch.rst b/docs/yow/branch.rst deleted file mode 100644 index fcf7fcc..0000000 --- a/docs/yow/branch.rst +++ /dev/null @@ -1,59 +0,0 @@ --------------- - -branch -^^^^^^^^ - -Basis Function Combinator - - -Use a Boolean value to select one of two quoted programs to run. - -:: - - branch == roll< choice i - -:: - - False [F] [T] branch - -------------------------- - F - - True [F] [T] branch - ------------------------- - T - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/ccccons.md b/docs/yow/ccccons.md deleted file mode 100644 index 5e97f91..0000000 --- a/docs/yow/ccccons.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# ccccons - -Basis Function Combinator - -ccons ccons - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/ccccons.rst b/docs/yow/ccccons.rst deleted file mode 100644 index 9e1fb32..0000000 --- a/docs/yow/ccccons.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -ccccons -^^^^^^^^^ - -Basis Function Combinator - -ccons ccons - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/choice.md b/docs/yow/choice.md deleted file mode 100644 index 9ec19cc..0000000 --- a/docs/yow/choice.md +++ /dev/null @@ -1,42 +0,0 @@ ------------------------------------------------------------------------- - -# choice - -Basis Function Combinator - -Use a Boolean value to select one of two items. : - - A B false choice - ---------------------- - A - - - A B true choice - --------------------- - B - -Currently Python semantics are used to evaluate the \"truthiness\" of -the Boolean value (so empty string, zero, etc. are counted as false, -etc.) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/choice.rst b/docs/yow/choice.rst deleted file mode 100644 index 44d3fb8..0000000 --- a/docs/yow/choice.rst +++ /dev/null @@ -1,57 +0,0 @@ --------------- - -choice -^^^^^^^^ - -Basis Function Combinator - - -Use a Boolean value to select one of two items. -:: - - A B false choice - ---------------------- - A - - - A B true choice - --------------------- - B - -Currently Python semantics are used to evaluate the "truthiness" of the -Boolean value (so empty string, zero, etc. are counted as false, etc.) - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/clear.md b/docs/yow/clear.md deleted file mode 100644 index e03d787..0000000 --- a/docs/yow/clear.md +++ /dev/null @@ -1,34 +0,0 @@ ------------------------------------------------------------------------- - -# clear - -Basis Function Combinator - -Clear everything from the stack. - -: clear == stack [pop stack] loop - - ... clear - --------------- - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/clear.rst b/docs/yow/clear.rst deleted file mode 100644 index a3a96c4..0000000 --- a/docs/yow/clear.rst +++ /dev/null @@ -1,50 +0,0 @@ --------------- - -clear -^^^^^^^ - -Basis Function Combinator - -Clear everything from the stack. - :: - - clear == stack [pop stack] loop - - ... clear - --------------- - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/cleave.md b/docs/yow/cleave.md deleted file mode 100644 index 632ecc1..0000000 --- a/docs/yow/cleave.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# cleave - -Basis Function Combinator - -fork popdd - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/cleave.rst b/docs/yow/cleave.rst deleted file mode 100644 index 45017d0..0000000 --- a/docs/yow/cleave.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -cleave -^^^^^^^^ - -Basis Function Combinator - -fork popdd - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/clop.md b/docs/yow/clop.md deleted file mode 100644 index 03b05c7..0000000 --- a/docs/yow/clop.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# clop - -Basis Function Combinator - -cleave popdd - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/clop.rst b/docs/yow/clop.rst deleted file mode 100644 index 4df41d8..0000000 --- a/docs/yow/clop.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -clop -^^^^^^ - -Basis Function Combinator - -cleave popdd - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/cmp.md b/docs/yow/cmp.md deleted file mode 100644 index c15a0f6..0000000 --- a/docs/yow/cmp.md +++ /dev/null @@ -1,42 +0,0 @@ ------------------------------------------------------------------------- - -# cmp - -Basis Function Combinator - -cmp takes two values and three quoted programs on the stack and runs one -of the three depending on the results of comparing the two values: : - - a b [G] [E] [L] cmp - ------------------------- a > b - G - - a b [G] [E] [L] cmp - ------------------------- a = b - E - - a b [G] [E] [L] cmp - ------------------------- a < b - L - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/cmp.rst b/docs/yow/cmp.rst deleted file mode 100644 index ac6e76e..0000000 --- a/docs/yow/cmp.rst +++ /dev/null @@ -1,58 +0,0 @@ --------------- - -cmp -^^^^^ - -Basis Function Combinator - - -cmp takes two values and three quoted programs on the stack and runs -one of the three depending on the results of comparing the two values: -:: - - a b [G] [E] [L] cmp - ------------------------- a > b - G - - a b [G] [E] [L] cmp - ------------------------- a = b - E - - a b [G] [E] [L] cmp - ------------------------- a < b - L - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/codi.md b/docs/yow/codi.md deleted file mode 100644 index 86637b3..0000000 --- a/docs/yow/codi.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# codi - -Basis Function Combinator - -cons dip - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/codi.rst b/docs/yow/codi.rst deleted file mode 100644 index 140718a..0000000 --- a/docs/yow/codi.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -codi -^^^^^^ - -Basis Function Combinator - -cons dip - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/codireco.md b/docs/yow/codireco.md deleted file mode 100644 index 26b90ec..0000000 --- a/docs/yow/codireco.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# codireco - -Basis Function Combinator - -codi reco - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/codireco.rst b/docs/yow/codireco.rst deleted file mode 100644 index 297e9fc..0000000 --- a/docs/yow/codireco.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -codireco -^^^^^^^^^^ - -Basis Function Combinator - -codi reco - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/concat.md b/docs/yow/concat.md deleted file mode 100644 index 8c9b8a9..0000000 --- a/docs/yow/concat.md +++ /dev/null @@ -1,33 +0,0 @@ ------------------------------------------------------------------------- - -# concat - -Basis Function Combinator - -Concatinate the two lists on the top of the stack. : - - [a b c] [d e f] concat - ---------------------------- - [a b c d e f] - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/concat.rst b/docs/yow/concat.rst deleted file mode 100644 index 1dd917f..0000000 --- a/docs/yow/concat.rst +++ /dev/null @@ -1,50 +0,0 @@ --------------- - -concat -^^^^^^^^ - -Basis Function Combinator - - -Concatinate the two lists on the top of the stack. -:: - - [a b c] [d e f] concat - ---------------------------- - [a b c d e f] - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/cond.md b/docs/yow/cond.md deleted file mode 100644 index c36450a..0000000 --- a/docs/yow/cond.md +++ /dev/null @@ -1,40 +0,0 @@ ------------------------------------------------------------------------- - -# cond - -Basis Function Combinator - -This combinator works like a case statement. It expects a single quote -on the stack that must contain zero or more condition quotes and a -default quote. Each condition clause should contain a quoted predicate -followed by the function expression to run if that predicate returns -true. If no predicates return true the default function runs. - -It works by rewriting into a chain of nested [ifte]{.title-ref} -expressions, e.g.: - - [[[B0] T0] [[B1] T1] [D]] cond - ----------------------------------------- - [B0] [T0] [[B1] [T1] [D] ifte] ifte - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/cond.rst b/docs/yow/cond.rst deleted file mode 100644 index 936585d..0000000 --- a/docs/yow/cond.rst +++ /dev/null @@ -1,55 +0,0 @@ --------------- - -cond -^^^^^^ - -Basis Function Combinator - - -This combinator works like a case statement. It expects a single quote -on the stack that must contain zero or more condition quotes and a -default quote. Each condition clause should contain a quoted predicate -followed by the function expression to run if that predicate returns -true. If no predicates return true the default function runs. - -It works by rewriting into a chain of nested `ifte` expressions, e.g.:: - - [[[B0] T0] [[B1] T1] [D]] cond - ----------------------------------------- - [B0] [T0] [[B1] [T1] [D] ifte] ifte - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dinfrirst.md b/docs/yow/dinfrirst.md deleted file mode 100644 index 3e14f9d..0000000 --- a/docs/yow/dinfrirst.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# dinfrirst - -Basis Function Combinator - -dip infrst - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dinfrirst.rst b/docs/yow/dinfrirst.rst deleted file mode 100644 index 242930e..0000000 --- a/docs/yow/dinfrirst.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -dinfrirst -^^^^^^^^^^^ - -Basis Function Combinator - -dip infrst - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dip.md b/docs/yow/dip.md deleted file mode 100644 index 1e67bcb..0000000 --- a/docs/yow/dip.md +++ /dev/null @@ -1,35 +0,0 @@ ------------------------------------------------------------------------- - -# dip - -Basis Function Combinator - -The dip combinator expects a quoted program on the stack and below it -some item, it hoists the item into the expression and runs the program -on the rest of the stack. : - - ... x [Q] dip - ------------------- - ... Q x - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dip.rst b/docs/yow/dip.rst deleted file mode 100644 index 9927f5a..0000000 --- a/docs/yow/dip.rst +++ /dev/null @@ -1,52 +0,0 @@ --------------- - -dip -^^^^^ - -Basis Function Combinator - - -The dip combinator expects a quoted program on the stack and below it -some item, it hoists the item into the expression and runs the program -on the rest of the stack. -:: - - ... x [Q] dip - ------------------- - ... Q x - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dipd.md b/docs/yow/dipd.md deleted file mode 100644 index 6ac590f..0000000 --- a/docs/yow/dipd.md +++ /dev/null @@ -1,33 +0,0 @@ ------------------------------------------------------------------------- - -# dipd - -Basis Function Combinator - -Like dip but expects two items. : - - ... y x [Q] dip - --------------------- - ... Q y x - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dipd.rst b/docs/yow/dipd.rst deleted file mode 100644 index 39705d7..0000000 --- a/docs/yow/dipd.rst +++ /dev/null @@ -1,50 +0,0 @@ --------------- - -dipd -^^^^^^ - -Basis Function Combinator - - -Like dip but expects two items. -:: - - ... y x [Q] dip - --------------------- - ... Q y x - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dipdd.md b/docs/yow/dipdd.md deleted file mode 100644 index ff18143..0000000 --- a/docs/yow/dipdd.md +++ /dev/null @@ -1,33 +0,0 @@ ------------------------------------------------------------------------- - -# dipdd - -Basis Function Combinator - -Like dip but expects three items. : - - ... z y x [Q] dip - ----------------------- - ... Q z y x - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dipdd.rst b/docs/yow/dipdd.rst deleted file mode 100644 index ba985bc..0000000 --- a/docs/yow/dipdd.rst +++ /dev/null @@ -1,50 +0,0 @@ --------------- - -dipdd -^^^^^^^ - -Basis Function Combinator - - -Like dip but expects three items. -:: - - ... z y x [Q] dip - ----------------------- - ... Q z y x - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/disenstacken.md b/docs/yow/disenstacken.md deleted file mode 100644 index 26ef6f7..0000000 --- a/docs/yow/disenstacken.md +++ /dev/null @@ -1,30 +0,0 @@ ------------------------------------------------------------------------- - -# disenstacken - -Basis Function Combinator - -The disenstacken operator expects a list on top of the stack and makes -that the stack discarding the rest of the stack. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/disenstacken.rst b/docs/yow/disenstacken.rst deleted file mode 100644 index c8333bd..0000000 --- a/docs/yow/disenstacken.rst +++ /dev/null @@ -1,45 +0,0 @@ --------------- - -disenstacken -^^^^^^^^^^^^^^ - -Basis Function Combinator - - -The disenstacken operator expects a list on top of the stack and makes that -the stack discarding the rest of the stack. - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/div.md b/docs/yow/div.md deleted file mode 100644 index 8042965..0000000 --- a/docs/yow/div.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# div - -See [floordiv](#floordiv). - diff --git a/docs/yow/div.rst b/docs/yow/div.rst deleted file mode 100644 index 0f8ac22..0000000 --- a/docs/yow/div.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -div -^^^^^ - -Basis Function Combinator - -Same as a // b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/divmod.md b/docs/yow/divmod.md deleted file mode 100644 index 302a632..0000000 --- a/docs/yow/divmod.md +++ /dev/null @@ -1,31 +0,0 @@ ------------------------------------------------------------------------- - -# divmod - -Basis Function Combinator - -divmod(x, y) -\> (quotient, remainder) - -Return the tuple (x//y, x%y). Invariant: q \* y + r == x. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/divmod.rst b/docs/yow/divmod.rst deleted file mode 100644 index 5e02d36..0000000 --- a/docs/yow/divmod.rst +++ /dev/null @@ -1,46 +0,0 @@ --------------- - -divmod -^^^^^^^^ - -Basis Function Combinator - - -divmod(x, y) -> (quotient, remainder) - -Return the tuple (x//y, x%y). Invariant: q * y + r == x. - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/down_to_zero.md b/docs/yow/down_to_zero.md deleted file mode 100644 index fc39245..0000000 --- a/docs/yow/down_to_zero.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# down_to_zero - -Basis Function Combinator - -\[0 \>\] \[dup \--\] while - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/down_to_zero.rst b/docs/yow/down_to_zero.rst deleted file mode 100644 index 61c44a0..0000000 --- a/docs/yow/down_to_zero.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -down_to_zero -^^^^^^^^^^^^^^ - -Basis Function Combinator - -[0 >] [dup --] while - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/drop.md b/docs/yow/drop.md deleted file mode 100644 index 52669af..0000000 --- a/docs/yow/drop.md +++ /dev/null @@ -1,36 +0,0 @@ ------------------------------------------------------------------------- - -# drop - -Basis Function Combinator - - drop == [rest] times - -Expects an integer and a quote on the stack and returns the quote with n -items removed off the top. : - - [a b c d] 2 drop - ---------------------- - [c d] - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/drop.rst b/docs/yow/drop.rst deleted file mode 100644 index 0172c32..0000000 --- a/docs/yow/drop.rst +++ /dev/null @@ -1,55 +0,0 @@ --------------- - -drop -^^^^^^ - -Basis Function Combinator - - -:: - - drop == [rest] times - -Expects an integer and a quote on the stack and returns the quote with -n items removed off the top. -:: - - [a b c d] 2 drop - ---------------------- - [c d] - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dup.md b/docs/yow/dup.md deleted file mode 100644 index 77f2025..0000000 --- a/docs/yow/dup.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# dup - -Basis Function Combinator - - (a1 -- a1 a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dup.rst b/docs/yow/dup.rst deleted file mode 100644 index 1d96a50..0000000 --- a/docs/yow/dup.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -dup -^^^^^ - -Basis Function Combinator - - -:: - - (a1 -- a1 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dupd.md b/docs/yow/dupd.md deleted file mode 100644 index b192108..0000000 --- a/docs/yow/dupd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# dupd - -Basis Function Combinator - - (a2 a1 -- a2 a2 a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dupd.rst b/docs/yow/dupd.rst deleted file mode 100644 index f75901b..0000000 --- a/docs/yow/dupd.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -dupd -^^^^^^ - -Basis Function Combinator - - -:: - - (a2 a1 -- a2 a2 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dupdd.md b/docs/yow/dupdd.md deleted file mode 100644 index edae234..0000000 --- a/docs/yow/dupdd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# dupdd - -Basis Function Combinator - - (a3 a2 a1 -- a3 a3 a2 a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dupdd.rst b/docs/yow/dupdd.rst deleted file mode 100644 index ff1dd1e..0000000 --- a/docs/yow/dupdd.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -dupdd -^^^^^^^ - -Basis Function Combinator - - -:: - - (a3 a2 a1 -- a3 a3 a2 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dupdip.md b/docs/yow/dupdip.md deleted file mode 100644 index a281ff7..0000000 --- a/docs/yow/dupdip.md +++ /dev/null @@ -1,34 +0,0 @@ ------------------------------------------------------------------------- - -# dupdip - -Basis Function Combinator - - [F] dupdip == dup [F] dip - - ... a [F] dupdip - ... a dup [F] dip - ... a a [F] dip - ... a F a - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dupdip.rst b/docs/yow/dupdip.rst deleted file mode 100644 index aa9431f..0000000 --- a/docs/yow/dupdip.rst +++ /dev/null @@ -1,52 +0,0 @@ --------------- - -dupdip -^^^^^^^^ - -Basis Function Combinator - - -:: - - [F] dupdip == dup [F] dip - - ... a [F] dupdip - ... a dup [F] dip - ... a a [F] dip - ... a F a - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/dupdipd.md b/docs/yow/dupdipd.md deleted file mode 100644 index 7246a1c..0000000 --- a/docs/yow/dupdipd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# dupdipd - -Basis Function Combinator - -dup dipd - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/dupdipd.rst b/docs/yow/dupdipd.rst deleted file mode 100644 index 4b149af..0000000 --- a/docs/yow/dupdipd.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -dupdipd -^^^^^^^^^ - -Basis Function Combinator - -dup dipd - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/enstacken.md b/docs/yow/enstacken.md deleted file mode 100644 index d2bfa87..0000000 --- a/docs/yow/enstacken.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# enstacken - -Basis Function Combinator - -stack \[clear\] dip - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/enstacken.rst b/docs/yow/enstacken.rst deleted file mode 100644 index 078526f..0000000 --- a/docs/yow/enstacken.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -enstacken -^^^^^^^^^^^ - -Basis Function Combinator - -stack [clear] dip - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/eq.md b/docs/yow/eq.md deleted file mode 100644 index a13a6b7..0000000 --- a/docs/yow/eq.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# eq - -Basis Function Combinator - -Same as a == b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/eq.rst b/docs/yow/eq.rst deleted file mode 100644 index 4bf1561..0000000 --- a/docs/yow/eq.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -eq -^^^^ - -Basis Function Combinator - -Same as a == b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/first.md b/docs/yow/first.md deleted file mode 100644 index 29e2419..0000000 --- a/docs/yow/first.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# first - -Basis Function Combinator - - ([a1 ...1] -- a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/first.rst b/docs/yow/first.rst deleted file mode 100644 index 6bb3e3a..0000000 --- a/docs/yow/first.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -first -^^^^^^^ - -Basis Function Combinator - - -:: - - ([a1 ...1] -- a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/first_two.md b/docs/yow/first_two.md deleted file mode 100644 index 47e4604..0000000 --- a/docs/yow/first_two.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# first_two - -Basis Function Combinator - - ([a1 a2 ...1] -- a1 a2) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/first_two.rst b/docs/yow/first_two.rst deleted file mode 100644 index af80b3b..0000000 --- a/docs/yow/first_two.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -first_two -^^^^^^^^^^^ - -Basis Function Combinator - - -:: - - ([a1 a2 ...1] -- a1 a2) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/flatten.md b/docs/yow/flatten.md deleted file mode 100644 index 3fec06e..0000000 --- a/docs/yow/flatten.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# flatten - -Basis Function Combinator - -\<{} \[concat\] step - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/flatten.rst b/docs/yow/flatten.rst deleted file mode 100644 index f697b8a..0000000 --- a/docs/yow/flatten.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -flatten -^^^^^^^^^ - -Basis Function Combinator - -<{} [concat] step - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/floor.md b/docs/yow/floor.md deleted file mode 100644 index af01826..0000000 --- a/docs/yow/floor.md +++ /dev/null @@ -1,31 +0,0 @@ ------------------------------------------------------------------------- - -# floor - -Basis Function Combinator - -Return the floor of x as an Integral. - -This is the largest integer \<= x. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/floor.rst b/docs/yow/floor.rst deleted file mode 100644 index b73544b..0000000 --- a/docs/yow/floor.rst +++ /dev/null @@ -1,44 +0,0 @@ --------------- - -floor -^^^^^^^ - -Basis Function Combinator - -Return the floor of x as an Integral. - -This is the largest integer <= x. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/floordiv.md b/docs/yow/floordiv.md deleted file mode 100644 index 11e8521..0000000 --- a/docs/yow/floordiv.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# floordiv - -Basis Function Combinator - -Same as a // b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/floordiv.rst b/docs/yow/floordiv.rst deleted file mode 100644 index 8b59590..0000000 --- a/docs/yow/floordiv.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -floordiv -^^^^^^^^^^ - -Basis Function Combinator - -Same as a // b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/fork.md b/docs/yow/fork.md deleted file mode 100644 index 01ff9c4..0000000 --- a/docs/yow/fork.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# fork - -Basis Function Combinator - -\[i\] app2 - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/fork.rst b/docs/yow/fork.rst deleted file mode 100644 index 18c68ba..0000000 --- a/docs/yow/fork.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -fork -^^^^^^ - -Basis Function Combinator - -[i] app2 - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/fourth.md b/docs/yow/fourth.md deleted file mode 100644 index 97c45e7..0000000 --- a/docs/yow/fourth.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# fourth - -Basis Function Combinator - - ([a1 a2 a3 a4 ...1] -- a4) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/fourth.rst b/docs/yow/fourth.rst deleted file mode 100644 index 420d50c..0000000 --- a/docs/yow/fourth.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -fourth -^^^^^^^^ - -Basis Function Combinator - - -:: - - ([a1 a2 a3 a4 ...1] -- a4) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/gcd.md b/docs/yow/gcd.md deleted file mode 100644 index a1c2d63..0000000 --- a/docs/yow/gcd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# gcd - -Basis Function Combinator - -true \[tuck mod dup 0 \>\] loop pop - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/gcd.rst b/docs/yow/gcd.rst deleted file mode 100644 index 0878163..0000000 --- a/docs/yow/gcd.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -gcd -^^^^^ - -Basis Function Combinator - -true [tuck mod dup 0 >] loop pop - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/gcd2.md b/docs/yow/gcd2.md deleted file mode 100644 index 02080e6..0000000 --- a/docs/yow/gcd2.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# gcd2 - -Basis Function Combinator - -Compiled GCD function. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/gcd2.rst b/docs/yow/gcd2.rst deleted file mode 100644 index f64fc95..0000000 --- a/docs/yow/gcd2.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -gcd2 -^^^^^^ - -Basis Function Combinator - -Compiled GCD function. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/ge.md b/docs/yow/ge.md deleted file mode 100644 index 87bc829..0000000 --- a/docs/yow/ge.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# ge - -Basis Function Combinator - -Same as a \>= b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/ge.rst b/docs/yow/ge.rst deleted file mode 100644 index 703f69d..0000000 --- a/docs/yow/ge.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -ge -^^^^ - -Basis Function Combinator - -Same as a >= b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/genrec.md b/docs/yow/genrec.md deleted file mode 100644 index 251dc54..0000000 --- a/docs/yow/genrec.md +++ /dev/null @@ -1,71 +0,0 @@ ------------------------------------------------------------------------- - -# genrec - -Basis Function Combinator - -General Recursion Combinator. : - - [if] [then] [rec1] [rec2] genrec - --------------------------------------------------------------------- - [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte - -From \"Recursion Theory and Joy\" (j05cmp.html) by Manfred von Thun: -\"The genrec combinator takes four program parameters in addition to -whatever data parameters it needs. Fourth from the top is an if-part, -followed by a then-part. If the if-part yields true, then the then-part -is executed and the combinator terminates. The other two parameters are -the rec1-part and the rec2-part. If the if-part yields false, the -rec1-part is executed. Following that the four program parameters and -the combinator are again pushed onto the stack bundled up in a quoted -form. Then the rec2-part is executed, where it will find the bundled -form. Typically it will then execute the bundled form, either with i or -with app2, or some other combinator.\" - -The way to design one of these is to fix your base case \[then\] and the -test \[if\], and then treat rec1 and rec2 as an else-part -\"sandwiching\" a quotation of the whole function. - -For example, given a (general recursive) function \'F\': : - - F == [I] [T] [R1] [R2] genrec - -If the \[I\] if-part fails you must derive R1 and R2 from: : - - ... R1 [F] R2 - -Just set the stack arguments in front, and figure out what R1 and R2 -have to do to apply the quoted \[F\] in the proper way. In effect, the -genrec combinator turns into an ifte combinator with a quoted copy of -the original definition in the else-part: : - - F == [I] [T] [R1] [R2] genrec - == [I] [T] [R1 [F] R2] ifte - -Primitive recursive functions are those where R2 == i. : - - P == [I] [T] [R] tailrec - == [I] [T] [R [P] i] ifte - == [I] [T] [R P] ifte - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/genrec.rst b/docs/yow/genrec.rst deleted file mode 100644 index c3d4c21..0000000 --- a/docs/yow/genrec.rst +++ /dev/null @@ -1,92 +0,0 @@ --------------- - -genrec -^^^^^^^^ - -Basis Function Combinator - - -General Recursion Combinator. -:: - - [if] [then] [rec1] [rec2] genrec - --------------------------------------------------------------------- - [if] [then] [rec1 [[if] [then] [rec1] [rec2] genrec] rec2] ifte - -From "Recursion Theory and Joy" (j05cmp.html) by Manfred von Thun: -"The genrec combinator takes four program parameters in addition to -whatever data parameters it needs. Fourth from the top is an if-part, -followed by a then-part. If the if-part yields true, then the then-part -is executed and the combinator terminates. The other two parameters are -the rec1-part and the rec2-part. If the if-part yields false, the -rec1-part is executed. Following that the four program parameters and -the combinator are again pushed onto the stack bundled up in a quoted -form. Then the rec2-part is executed, where it will find the bundled -form. Typically it will then execute the bundled form, either with i or -with app2, or some other combinator." - -The way to design one of these is to fix your base case [then] and the -test [if], and then treat rec1 and rec2 as an else-part "sandwiching" -a quotation of the whole function. - -For example, given a (general recursive) function 'F': -:: - - F == [I] [T] [R1] [R2] genrec - -If the [I] if-part fails you must derive R1 and R2 from: -:: - - ... R1 [F] R2 - -Just set the stack arguments in front, and figure out what R1 and R2 -have to do to apply the quoted [F] in the proper way. In effect, the -genrec combinator turns into an ifte combinator with a quoted copy of -the original definition in the else-part: -:: - - F == [I] [T] [R1] [R2] genrec - == [I] [T] [R1 [F] R2] ifte - -Primitive recursive functions are those where R2 == i. -:: - - P == [I] [T] [R] tailrec - == [I] [T] [R [P] i] ifte - == [I] [T] [R P] ifte - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/getitem.md b/docs/yow/getitem.md deleted file mode 100644 index 08a504d..0000000 --- a/docs/yow/getitem.md +++ /dev/null @@ -1,36 +0,0 @@ ------------------------------------------------------------------------- - -# getitem - -Basis Function Combinator - - getitem == drop first - -Expects an integer and a quote on the stack and returns the item at the -nth position in the quote counting from 0. : - - [a b c d] 0 getitem - ------------------------- - a - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/getitem.rst b/docs/yow/getitem.rst deleted file mode 100644 index 7fcb6f9..0000000 --- a/docs/yow/getitem.rst +++ /dev/null @@ -1,55 +0,0 @@ --------------- - -getitem -^^^^^^^^^ - -Basis Function Combinator - - -:: - - getitem == drop first - -Expects an integer and a quote on the stack and returns the item at the -nth position in the quote counting from 0. -:: - - [a b c d] 0 getitem - ------------------------- - a - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/grabN.md b/docs/yow/grabN.md deleted file mode 100644 index 3a5a5fe..0000000 --- a/docs/yow/grabN.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# grabN - -Basis Function Combinator - -\<{} \[cons\] times - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/grabN.rst b/docs/yow/grabN.rst deleted file mode 100644 index 268277c..0000000 --- a/docs/yow/grabN.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -grabN -^^^^^^^ - -Basis Function Combinator - -<{} [cons] times - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/grba.md b/docs/yow/grba.md deleted file mode 100644 index 69a7e04..0000000 --- a/docs/yow/grba.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# grba - -Basis Function Combinator - -\[stack popd\] dip - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/grba.rst b/docs/yow/grba.rst deleted file mode 100644 index 5c4d4d8..0000000 --- a/docs/yow/grba.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -grba -^^^^^^ - -Basis Function Combinator - -[stack popd] dip - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/gt.md b/docs/yow/gt.md deleted file mode 100644 index d9f778b..0000000 --- a/docs/yow/gt.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# gt - -Basis Function Combinator - -Same as a \> b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/gt.rst b/docs/yow/gt.rst deleted file mode 100644 index ece1718..0000000 --- a/docs/yow/gt.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -gt -^^^^ - -Basis Function Combinator - -Same as a > b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/help.md b/docs/yow/help.md deleted file mode 100644 index ce9ac60..0000000 --- a/docs/yow/help.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# help - -Basis Function Combinator - -Accepts a quoted symbol on the top of the stack and prints its docs. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/help.rst b/docs/yow/help.rst deleted file mode 100644 index 3da0d5c..0000000 --- a/docs/yow/help.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -help -^^^^^^ - -Basis Function Combinator - -Accepts a quoted symbol on the top of the stack and prints its docs. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/hypot.md b/docs/yow/hypot.md deleted file mode 100644 index 8635dfc..0000000 --- a/docs/yow/hypot.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# hypot - -Basis Function Combinator - -\[sqr\] ii + sqrt - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/hypot.rst b/docs/yow/hypot.rst deleted file mode 100644 index 542dcf1..0000000 --- a/docs/yow/hypot.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -hypot -^^^^^^^ - -Basis Function Combinator - -[sqr] ii + sqrt - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/id.md b/docs/yow/id.md deleted file mode 100644 index 085e0a6..0000000 --- a/docs/yow/id.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# id - -Basis Function Combinator - -The identity function. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/id.rst b/docs/yow/id.rst deleted file mode 100644 index f2263a3..0000000 --- a/docs/yow/id.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -id -^^^^ - -Basis Function Combinator - -The identity function. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/ifte.md b/docs/yow/ifte.md deleted file mode 100644 index 00548fd..0000000 --- a/docs/yow/ifte.md +++ /dev/null @@ -1,43 +0,0 @@ ------------------------------------------------------------------------- - -# ifte - -Basis Function Combinator - -If-Then-Else Combinator : - - ... [if] [then] [else] ifte - --------------------------------------------------- - ... [[else] [then]] [...] [if] infra select i - - - - - ... [if] [then] [else] ifte - ------------------------------------------------------- - ... [else] [then] [...] [if] infra first choice i - -Has the effect of grabbing a copy of the stack on which to run the -if-part using infra. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/ifte.rst b/docs/yow/ifte.rst deleted file mode 100644 index 1cf0070..0000000 --- a/docs/yow/ifte.rst +++ /dev/null @@ -1,60 +0,0 @@ --------------- - -ifte -^^^^^^ - -Basis Function Combinator - - -If-Then-Else Combinator -:: - - ... [if] [then] [else] ifte - --------------------------------------------------- - ... [[else] [then]] [...] [if] infra select i - - - - - ... [if] [then] [else] ifte - ------------------------------------------------------- - ... [else] [then] [...] [if] infra first choice i - - -Has the effect of grabbing a copy of the stack on which to run the -if-part using infra. - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/ii.md b/docs/yow/ii.md deleted file mode 100644 index 5921236..0000000 --- a/docs/yow/ii.md +++ /dev/null @@ -1,31 +0,0 @@ ------------------------------------------------------------------------- - -# ii - -Basis Function Combinator - - ... a [Q] ii - ------------------ - ... Q a Q - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/ii.rst b/docs/yow/ii.rst deleted file mode 100644 index 0f13620..0000000 --- a/docs/yow/ii.rst +++ /dev/null @@ -1,49 +0,0 @@ --------------- - -ii -^^^^ - -Basis Function Combinator - - -:: - - ... a [Q] ii - ------------------ - ... Q a Q - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/infrst.md b/docs/yow/infrst.md deleted file mode 100644 index b091159..0000000 --- a/docs/yow/infrst.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# infrst - -Basis Function Combinator - -infra first - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/infrst.rst b/docs/yow/infrst.rst deleted file mode 100644 index 72b9989..0000000 --- a/docs/yow/infrst.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -infrst -^^^^^^^^ - -Basis Function Combinator - -infra first - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/inscribe.md b/docs/yow/inscribe.md deleted file mode 100644 index dbc9bb8..0000000 --- a/docs/yow/inscribe.md +++ /dev/null @@ -1,33 +0,0 @@ ------------------------------------------------------------------------- - -# inscribe - -Basis Function Combinator - -Create a new Joy function definition in the Joy dictionary. A definition -is given as a quote with a name followed by a Joy expression. for -example: - -> \[sqr dup mul\] inscribe - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/inscribe.rst b/docs/yow/inscribe.rst deleted file mode 100644 index c3913bb..0000000 --- a/docs/yow/inscribe.rst +++ /dev/null @@ -1,49 +0,0 @@ --------------- - -inscribe -^^^^^^^^^^ - -Basis Function Combinator - - -Create a new Joy function definition in the Joy dictionary. A -definition is given as a quote with a name followed by a Joy -expression. for example: - - [sqr dup mul] inscribe - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/le.md b/docs/yow/le.md deleted file mode 100644 index 4e09955..0000000 --- a/docs/yow/le.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# le - -Basis Function Combinator - -Same as a \<= b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/le.rst b/docs/yow/le.rst deleted file mode 100644 index 79c7086..0000000 --- a/docs/yow/le.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -le -^^^^ - -Basis Function Combinator - -Same as a <= b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/loop.md b/docs/yow/loop.md deleted file mode 100644 index efa212b..0000000 --- a/docs/yow/loop.md +++ /dev/null @@ -1,37 +0,0 @@ ------------------------------------------------------------------------- - -# loop - -Basis Function Combinator - -Basic loop combinator. : - - ... True [Q] loop - ----------------------- - ... Q [Q] loop - - ... False [Q] loop - ------------------------ - ... - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/loop.rst b/docs/yow/loop.rst deleted file mode 100644 index 911152a..0000000 --- a/docs/yow/loop.rst +++ /dev/null @@ -1,54 +0,0 @@ --------------- - -loop -^^^^^^ - -Basis Function Combinator - - -Basic loop combinator. -:: - - ... True [Q] loop - ----------------------- - ... Q [Q] loop - - ... False [Q] loop - ------------------------ - ... - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/lshift.md b/docs/yow/lshift.md deleted file mode 100644 index 9ed89be..0000000 --- a/docs/yow/lshift.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# lshift - -Basis Function Combinator - -Same as a \<\< b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/lshift.rst b/docs/yow/lshift.rst deleted file mode 100644 index 5327dd7..0000000 --- a/docs/yow/lshift.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -lshift -^^^^^^^^ - -Basis Function Combinator - -Same as a << b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/lt.md b/docs/yow/lt.md deleted file mode 100644 index 196e1f8..0000000 --- a/docs/yow/lt.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# lt - -Basis Function Combinator - -Same as a \< b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/lt.rst b/docs/yow/lt.rst deleted file mode 100644 index 68f221c..0000000 --- a/docs/yow/lt.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -lt -^^^^ - -Basis Function Combinator - -Same as a < b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/make_generator.md b/docs/yow/make_generator.md deleted file mode 100644 index 12bee0e..0000000 --- a/docs/yow/make_generator.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# make_generator - -Basis Function Combinator - -\[codireco\] ccons - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/make_generator.rst b/docs/yow/make_generator.rst deleted file mode 100644 index 0220a81..0000000 --- a/docs/yow/make_generator.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -make_generator -^^^^^^^^^^^^^^^^ - -Basis Function Combinator - -[codireco] ccons - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/map.md b/docs/yow/map.md deleted file mode 100644 index 9e951bc..0000000 --- a/docs/yow/map.md +++ /dev/null @@ -1,30 +0,0 @@ ------------------------------------------------------------------------- - -# map - -Basis Function Combinator - -Run the quoted program on TOS on the items in the list under it, push a -new list with the results in place of the program and original list. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/map.rst b/docs/yow/map.rst deleted file mode 100644 index e7dd4f9..0000000 --- a/docs/yow/map.rst +++ /dev/null @@ -1,45 +0,0 @@ --------------- - -map -^^^^^ - -Basis Function Combinator - - -Run the quoted program on TOS on the items in the list under it, push a -new list with the results in place of the program and original list. - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/max.md b/docs/yow/max.md deleted file mode 100644 index c80177c..0000000 --- a/docs/yow/max.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# max - -Basis Function Combinator - -Given a list find the maximum. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/max.rst b/docs/yow/max.rst deleted file mode 100644 index 06ad53f..0000000 --- a/docs/yow/max.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -max -^^^^^ - -Basis Function Combinator - -Given a list find the maximum. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/min.md b/docs/yow/min.md deleted file mode 100644 index ee89455..0000000 --- a/docs/yow/min.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# min - -Basis Function Combinator - -Given a list find the minimum. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/min.rst b/docs/yow/min.rst deleted file mode 100644 index 6c877a7..0000000 --- a/docs/yow/min.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -min -^^^^^ - -Basis Function Combinator - -Given a list find the minimum. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/mod.md b/docs/yow/mod.md deleted file mode 100644 index 7630571..0000000 --- a/docs/yow/mod.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# mod - -Basis Function Combinator - -Same as a % b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/mod.rst b/docs/yow/mod.rst deleted file mode 100644 index 390b428..0000000 --- a/docs/yow/mod.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -mod -^^^^^ - -Basis Function Combinator - -Same as a % b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/modulus.md b/docs/yow/modulus.md deleted file mode 100644 index dcd5513..0000000 --- a/docs/yow/modulus.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# modulus - -See [mod](#mod). - diff --git a/docs/yow/modulus.rst b/docs/yow/modulus.rst deleted file mode 100644 index 054b66b..0000000 --- a/docs/yow/modulus.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -modulus -^^^^^^^^^ - -Basis Function Combinator - -Same as a % b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/mul.md b/docs/yow/mul.md deleted file mode 100644 index e494646..0000000 --- a/docs/yow/mul.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# mul - -Basis Function Combinator - -Same as a \* b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/mul.rst b/docs/yow/mul.rst deleted file mode 100644 index 6a66488..0000000 --- a/docs/yow/mul.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -mul -^^^^^ - -Basis Function Combinator - -Same as a * b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/ne.md b/docs/yow/ne.md deleted file mode 100644 index a2dc5d3..0000000 --- a/docs/yow/ne.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# ne - -Basis Function Combinator - -Same as a != b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/ne.rst b/docs/yow/ne.rst deleted file mode 100644 index ac9aa32..0000000 --- a/docs/yow/ne.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -ne -^^^^ - -Basis Function Combinator - -Same as a != b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/neg.md b/docs/yow/neg.md deleted file mode 100644 index fa4e7ce..0000000 --- a/docs/yow/neg.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# neg - -Basis Function Combinator - -Same as -a. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/neg.rst b/docs/yow/neg.rst deleted file mode 100644 index 76e2f70..0000000 --- a/docs/yow/neg.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -neg -^^^^^ - -Basis Function Combinator - -Same as -a. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/not.md b/docs/yow/not.md deleted file mode 100644 index d628058..0000000 --- a/docs/yow/not.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# not - -Basis Function Combinator - -Same as not a. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/not.rst b/docs/yow/not.rst deleted file mode 100644 index 3aca650..0000000 --- a/docs/yow/not.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -not -^^^^^ - -Basis Function Combinator - -Same as not a. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/nulco.md b/docs/yow/nulco.md deleted file mode 100644 index c54e71b..0000000 --- a/docs/yow/nulco.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# nulco - -Basis Function Combinator - -\[nullary\] cons - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/nulco.rst b/docs/yow/nulco.rst deleted file mode 100644 index 8f62e16..0000000 --- a/docs/yow/nulco.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -nulco -^^^^^^^ - -Basis Function Combinator - -[nullary] cons - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/of.md b/docs/yow/of.md deleted file mode 100644 index 7fa80d9..0000000 --- a/docs/yow/of.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# of - -Basis Function Combinator - -swap at - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/of.rst b/docs/yow/of.rst deleted file mode 100644 index cedccec..0000000 --- a/docs/yow/of.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -of -^^^^ - -Basis Function Combinator - -swap at - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/or.md b/docs/yow/or.md deleted file mode 100644 index dc2b1a1..0000000 --- a/docs/yow/or.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# or - -Basis Function Combinator - -Same as a \| b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/or.rst b/docs/yow/or.rst deleted file mode 100644 index b5d3a9a..0000000 --- a/docs/yow/or.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -or -^^^^ - -Basis Function Combinator - -Same as a | b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/over.md b/docs/yow/over.md deleted file mode 100644 index c2e49ec..0000000 --- a/docs/yow/over.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# over - -Basis Function Combinator - - (a2 a1 -- a2 a1 a2) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/over.rst b/docs/yow/over.rst deleted file mode 100644 index 7a32b0f..0000000 --- a/docs/yow/over.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -over -^^^^^^ - -Basis Function Combinator - - -:: - - (a2 a1 -- a2 a1 a2) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/pam.md b/docs/yow/pam.md deleted file mode 100644 index d02292c..0000000 --- a/docs/yow/pam.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# pam - -Basis Function Combinator - -\[i\] map - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/pam.rst b/docs/yow/pam.rst deleted file mode 100644 index 8237ebe..0000000 --- a/docs/yow/pam.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -pam -^^^^^ - -Basis Function Combinator - -[i] map - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/pick.md b/docs/yow/pick.md deleted file mode 100644 index fad2ad3..0000000 --- a/docs/yow/pick.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# pick - -See [getitem](#getitem). - diff --git a/docs/yow/pick.rst b/docs/yow/pick.rst deleted file mode 100644 index 72e1bbc..0000000 --- a/docs/yow/pick.rst +++ /dev/null @@ -1,55 +0,0 @@ --------------- - -pick -^^^^^^ - -Basis Function Combinator - - -:: - - getitem == drop first - -Expects an integer and a quote on the stack and returns the item at the -nth position in the quote counting from 0. -:: - - [a b c d] 0 getitem - ------------------------- - a - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/pm.md b/docs/yow/pm.md deleted file mode 100644 index 6534d7e..0000000 --- a/docs/yow/pm.md +++ /dev/null @@ -1,33 +0,0 @@ ------------------------------------------------------------------------- - -# pm - -Basis Function Combinator - -Plus or minus : - - a b pm - ------------- - a+b a-b - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/pm.rst b/docs/yow/pm.rst deleted file mode 100644 index 397db01..0000000 --- a/docs/yow/pm.rst +++ /dev/null @@ -1,50 +0,0 @@ --------------- - -pm -^^^^ - -Basis Function Combinator - - -Plus or minus -:: - - a b pm - ------------- - a+b a-b - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/pop.md b/docs/yow/pop.md deleted file mode 100644 index dcb6cbc..0000000 --- a/docs/yow/pop.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# pop - -Basis Function Combinator - - (a1 --) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/pop.rst b/docs/yow/pop.rst deleted file mode 100644 index f4e419d..0000000 --- a/docs/yow/pop.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -pop -^^^^^ - -Basis Function Combinator - - -:: - - (a1 --) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/popd.md b/docs/yow/popd.md deleted file mode 100644 index eaacad4..0000000 --- a/docs/yow/popd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# popd - -Basis Function Combinator - - (a2 a1 -- a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/popd.rst b/docs/yow/popd.rst deleted file mode 100644 index ebdf887..0000000 --- a/docs/yow/popd.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -popd -^^^^^^ - -Basis Function Combinator - - -:: - - (a2 a1 -- a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/popdd.md b/docs/yow/popdd.md deleted file mode 100644 index 1d78b67..0000000 --- a/docs/yow/popdd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# popdd - -Basis Function Combinator - - (a3 a2 a1 -- a2 a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/popdd.rst b/docs/yow/popdd.rst deleted file mode 100644 index c12ad20..0000000 --- a/docs/yow/popdd.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -popdd -^^^^^^^ - -Basis Function Combinator - - -:: - - (a3 a2 a1 -- a2 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/popop.md b/docs/yow/popop.md deleted file mode 100644 index 0029d33..0000000 --- a/docs/yow/popop.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# popop - -Basis Function Combinator - - (a2 a1 --) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/popop.rst b/docs/yow/popop.rst deleted file mode 100644 index dde46f0..0000000 --- a/docs/yow/popop.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -popop -^^^^^^^ - -Basis Function Combinator - - -:: - - (a2 a1 --) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/popopd.md b/docs/yow/popopd.md deleted file mode 100644 index 8db9175..0000000 --- a/docs/yow/popopd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# popopd - -Basis Function Combinator - - (a3 a2 a1 -- a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/popopd.rst b/docs/yow/popopd.rst deleted file mode 100644 index 6faab31..0000000 --- a/docs/yow/popopd.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -popopd -^^^^^^^^ - -Basis Function Combinator - - -:: - - (a3 a2 a1 -- a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/popopdd.md b/docs/yow/popopdd.md deleted file mode 100644 index 0ce33c1..0000000 --- a/docs/yow/popopdd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# popopdd - -Basis Function Combinator - - (a4 a3 a2 a1 -- a2 a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/popopdd.rst b/docs/yow/popopdd.rst deleted file mode 100644 index b2ac300..0000000 --- a/docs/yow/popopdd.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -popopdd -^^^^^^^^^ - -Basis Function Combinator - - -:: - - (a4 a3 a2 a1 -- a2 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/popopop.md b/docs/yow/popopop.md deleted file mode 100644 index 71e653d..0000000 --- a/docs/yow/popopop.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# popopop - -Basis Function Combinator - -pop popop - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/popopop.rst b/docs/yow/popopop.rst deleted file mode 100644 index aa44703..0000000 --- a/docs/yow/popopop.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -popopop -^^^^^^^^^ - -Basis Function Combinator - -pop popop - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/pow.md b/docs/yow/pow.md deleted file mode 100644 index ce76319..0000000 --- a/docs/yow/pow.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# pow - -Basis Function Combinator - -Same as a \*\* b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/pow.rst b/docs/yow/pow.rst deleted file mode 100644 index b876424..0000000 --- a/docs/yow/pow.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -pow -^^^^^ - -Basis Function Combinator - -Same as a ** b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/pred.md b/docs/yow/pred.md deleted file mode 100644 index 18e643b..0000000 --- a/docs/yow/pred.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# pred - -Basis Function Combinator - -Decrement TOS. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/pred.rst b/docs/yow/pred.rst deleted file mode 100644 index 6790934..0000000 --- a/docs/yow/pred.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -pred -^^^^^^ - -Basis Function Combinator - -Decrement TOS. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/primrec.md b/docs/yow/primrec.md deleted file mode 100644 index b7490ad..0000000 --- a/docs/yow/primrec.md +++ /dev/null @@ -1,56 +0,0 @@ ------------------------------------------------------------------------- - -# primrec - -Basis Function Combinator - -From the \"Overview of the language JOY\": - -\> The primrec combinator expects two quoted programs in addition to a -data parameter. For an integer data parameter it works like this: If the -data parameter is zero, then the first quotation has to produce the -value to be returned. If the data parameter is positive then the second -has to combine the data parameter with the result of applying the -function to its predecessor.: - - 5 [1] [*] primrec - -\> Then primrec tests whether the top element on the stack (initially -the 5) is equal to zero. If it is, it pops it off and executes one of -the quotations, the \[1\] which leaves 1 on the stack as the result. -Otherwise it pushes a decremented copy of the top element and recurses. -On the way back from the recursion it uses the other quotation, \[\*\], -to multiply what is now a factorial on top of the stack by the second -element on the stack.: - - n [Base] [Recur] primrec - - 0 [Base] [Recur] primrec - ------------------------------ - Base - - n [Base] [Recur] primrec - ------------------------------------------ n > 0 - n (n-1) [Base] [Recur] primrec Recur - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/primrec.rst b/docs/yow/primrec.rst deleted file mode 100644 index b60678e..0000000 --- a/docs/yow/primrec.rst +++ /dev/null @@ -1,72 +0,0 @@ --------------- - -primrec -^^^^^^^^^ - -Basis Function Combinator - - -From the "Overview of the language JOY": - -> The primrec combinator expects two quoted programs in addition to a -data parameter. For an integer data parameter it works like this: If -the data parameter is zero, then the first quotation has to produce -the value to be returned. If the data parameter is positive then the -second has to combine the data parameter with the result of applying -the function to its predecessor.:: - - 5 [1] [*] primrec - -> Then primrec tests whether the top element on the stack (initially -the 5) is equal to zero. If it is, it pops it off and executes one of -the quotations, the [1] which leaves 1 on the stack as the result. -Otherwise it pushes a decremented copy of the top element and -recurses. On the way back from the recursion it uses the other -quotation, [*], to multiply what is now a factorial on top of the -stack by the second element on the stack.:: - - n [Base] [Recur] primrec - - 0 [Base] [Recur] primrec - ------------------------------ - Base - - n [Base] [Recur] primrec - ------------------------------------------ n > 0 - n (n-1) [Base] [Recur] primrec Recur - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/product.md b/docs/yow/product.md deleted file mode 100644 index 38b3500..0000000 --- a/docs/yow/product.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# product - -Basis Function Combinator - -1 swap \[\*\] step - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/product.rst b/docs/yow/product.rst deleted file mode 100644 index 46ec501..0000000 --- a/docs/yow/product.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -product -^^^^^^^^^ - -Basis Function Combinator - -1 swap [*] step - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/quoted.md b/docs/yow/quoted.md deleted file mode 100644 index 7bb8aef..0000000 --- a/docs/yow/quoted.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# quoted - -Basis Function Combinator - -\[unit\] dip - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/quoted.rst b/docs/yow/quoted.rst deleted file mode 100644 index a3bc081..0000000 --- a/docs/yow/quoted.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -quoted -^^^^^^^^ - -Basis Function Combinator - -[unit] dip - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/range.md b/docs/yow/range.md deleted file mode 100644 index 327d860..0000000 --- a/docs/yow/range.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# range - -Basis Function Combinator - -\[0 \<=\] \[1 - dup\] anamorphism - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/range.rst b/docs/yow/range.rst deleted file mode 100644 index 8b65854..0000000 --- a/docs/yow/range.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -range -^^^^^^^ - -Basis Function Combinator - -[0 <=] [1 - dup] anamorphism - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/range_to_zero.md b/docs/yow/range_to_zero.md deleted file mode 100644 index 25e2e48..0000000 --- a/docs/yow/range_to_zero.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# range_to_zero - -Basis Function Combinator - -unit \[down_to_zero\] infra - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/range_to_zero.rst b/docs/yow/range_to_zero.rst deleted file mode 100644 index bc86bc2..0000000 --- a/docs/yow/range_to_zero.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -range_to_zero -^^^^^^^^^^^^^^^ - -Basis Function Combinator - -unit [down_to_zero] infra - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/reco.md b/docs/yow/reco.md deleted file mode 100644 index 5051e21..0000000 --- a/docs/yow/reco.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# reco - -Basis Function Combinator - -rest cons - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/reco.rst b/docs/yow/reco.rst deleted file mode 100644 index 9efaab8..0000000 --- a/docs/yow/reco.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -reco -^^^^^^ - -Basis Function Combinator - -rest cons - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/rem.md b/docs/yow/rem.md deleted file mode 100644 index 0531e3f..0000000 --- a/docs/yow/rem.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# rem - -See [mod](#mod). - diff --git a/docs/yow/rem.rst b/docs/yow/rem.rst deleted file mode 100644 index 6e5dd6a..0000000 --- a/docs/yow/rem.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -rem -^^^^^ - -Basis Function Combinator - -Same as a % b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/remainder.md b/docs/yow/remainder.md deleted file mode 100644 index 97bdd1c..0000000 --- a/docs/yow/remainder.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# remainder - -See [mod](#mod). - diff --git a/docs/yow/remainder.rst b/docs/yow/remainder.rst deleted file mode 100644 index 268ede7..0000000 --- a/docs/yow/remainder.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -remainder -^^^^^^^^^^^ - -Basis Function Combinator - -Same as a % b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/remove.md b/docs/yow/remove.md deleted file mode 100644 index 4c7154e..0000000 --- a/docs/yow/remove.md +++ /dev/null @@ -1,35 +0,0 @@ ------------------------------------------------------------------------- - -# remove - -Basis Function Combinator - -Expects an item on the stack and a quote under it and removes that item -from the the quote. The item is only removed once. If the list is empty -or the item isn\'t in the list then the list is unchanged. : - - [1 2 3 1] 1 remove - ------------------------ - [2 3 1] - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/remove.rst b/docs/yow/remove.rst deleted file mode 100644 index 0fb1693..0000000 --- a/docs/yow/remove.rst +++ /dev/null @@ -1,52 +0,0 @@ --------------- - -remove -^^^^^^^^ - -Basis Function Combinator - - -Expects an item on the stack and a quote under it and removes that item -from the the quote. The item is only removed once. If the list is -empty or the item isn't in the list then the list is unchanged. -:: - - [1 2 3 1] 1 remove - ------------------------ - [2 3 1] - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/rest.md b/docs/yow/rest.md deleted file mode 100644 index a819b91..0000000 --- a/docs/yow/rest.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# rest - -Basis Function Combinator - - ([a1 ...0] -- [...0]) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/rest.rst b/docs/yow/rest.rst deleted file mode 100644 index 004624e..0000000 --- a/docs/yow/rest.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -rest -^^^^^^ - -Basis Function Combinator - - -:: - - ([a1 ...0] -- [...0]) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/reverse.md b/docs/yow/reverse.md deleted file mode 100644 index 8551d8e..0000000 --- a/docs/yow/reverse.md +++ /dev/null @@ -1,31 +0,0 @@ ------------------------------------------------------------------------- - -# reverse - -Basis Function Combinator - -Reverse the list on the top of the stack. : - - reverse == [] swap shunt - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/reverse.rst b/docs/yow/reverse.rst deleted file mode 100644 index e76e8f3..0000000 --- a/docs/yow/reverse.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -reverse -^^^^^^^^^ - -Basis Function Combinator - - -Reverse the list on the top of the stack. -:: - - reverse == [] swap shunt - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/rolldown.md b/docs/yow/rolldown.md deleted file mode 100644 index 408e791..0000000 --- a/docs/yow/rolldown.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# rolldown - -Basis Function Combinator - - (a1 a2 a3 -- a2 a3 a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/rolldown.rst b/docs/yow/rolldown.rst deleted file mode 100644 index f0cc392..0000000 --- a/docs/yow/rolldown.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -rolldown -^^^^^^^^^^ - -Basis Function Combinator - - -:: - - (a1 a2 a3 -- a2 a3 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/rollup.md b/docs/yow/rollup.md deleted file mode 100644 index 0d43217..0000000 --- a/docs/yow/rollup.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# rollup - -Basis Function Combinator - - (a1 a2 a3 -- a3 a1 a2) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/rollup.rst b/docs/yow/rollup.rst deleted file mode 100644 index 6bf8138..0000000 --- a/docs/yow/rollup.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -rollup -^^^^^^^^ - -Basis Function Combinator - - -:: - - (a1 a2 a3 -- a3 a1 a2) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/roll•GREATER-THAN-SIGN.md b/docs/yow/roll•GREATER-THAN-SIGN.md deleted file mode 100644 index 5305114..0000000 --- a/docs/yow/roll•GREATER-THAN-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# roll> - -See [rollup](#rollup). - diff --git a/docs/yow/roll•GREATER-THAN-SIGN.rst b/docs/yow/roll•GREATER-THAN-SIGN.rst deleted file mode 100644 index 5e2bac4..0000000 --- a/docs/yow/roll•GREATER-THAN-SIGN.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -roll> -^^^^^^^ - -Basis Function Combinator - - -:: - - (a1 a2 a3 -- a3 a1 a2) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/roll•LESS-THAN-SIGN.md b/docs/yow/roll•LESS-THAN-SIGN.md deleted file mode 100644 index de6a5b2..0000000 --- a/docs/yow/roll•LESS-THAN-SIGN.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# roll< - -See [rolldown](#rolldown). - diff --git a/docs/yow/roll•LESS-THAN-SIGN.rst b/docs/yow/roll•LESS-THAN-SIGN.rst deleted file mode 100644 index a1ff5c3..0000000 --- a/docs/yow/roll•LESS-THAN-SIGN.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -roll< -^^^^^^^ - -Basis Function Combinator - - -:: - - (a1 a2 a3 -- a2 a3 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/round.md b/docs/yow/round.md deleted file mode 100644 index af45d60..0000000 --- a/docs/yow/round.md +++ /dev/null @@ -1,33 +0,0 @@ ------------------------------------------------------------------------- - -# round - -Basis Function Combinator - -Round a number to a given precision in decimal digits. - -The return value is an integer if ndigits is omitted or None. Otherwise -the return value has the same type as the number. ndigits may be -negative. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/round.rst b/docs/yow/round.rst deleted file mode 100644 index 81a500f..0000000 --- a/docs/yow/round.rst +++ /dev/null @@ -1,45 +0,0 @@ --------------- - -round -^^^^^^^ - -Basis Function Combinator - -Round a number to a given precision in decimal digits. - -The return value is an integer if ndigits is omitted or None. Otherwise -the return value has the same type as the number. ndigits may be negative. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/rrest.md b/docs/yow/rrest.md deleted file mode 100644 index 01ec510..0000000 --- a/docs/yow/rrest.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# rrest - -Basis Function Combinator - - ([a1 a2 ...1] -- [...1]) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/rrest.rst b/docs/yow/rrest.rst deleted file mode 100644 index c599070..0000000 --- a/docs/yow/rrest.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -rrest -^^^^^^^ - -Basis Function Combinator - - -:: - - ([a1 a2 ...1] -- [...1]) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/rshift.md b/docs/yow/rshift.md deleted file mode 100644 index bb265d8..0000000 --- a/docs/yow/rshift.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# rshift - -Basis Function Combinator - -Same as a \>\> b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/rshift.rst b/docs/yow/rshift.rst deleted file mode 100644 index 075c0a5..0000000 --- a/docs/yow/rshift.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -rshift -^^^^^^^^ - -Basis Function Combinator - -Same as a >> b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/run.md b/docs/yow/run.md deleted file mode 100644 index 381ef6c..0000000 --- a/docs/yow/run.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# run - -Basis Function Combinator - -\<{} infra - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/run.rst b/docs/yow/run.rst deleted file mode 100644 index cd144ef..0000000 --- a/docs/yow/run.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -run -^^^^^ - -Basis Function Combinator - -<{} infra - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/second.md b/docs/yow/second.md deleted file mode 100644 index 0f8e24b..0000000 --- a/docs/yow/second.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# second - -Basis Function Combinator - - ([a1 a2 ...1] -- a2) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/second.rst b/docs/yow/second.rst deleted file mode 100644 index 3fa9e0e..0000000 --- a/docs/yow/second.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -second -^^^^^^^^ - -Basis Function Combinator - - -:: - - ([a1 a2 ...1] -- a2) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/select.md b/docs/yow/select.md deleted file mode 100644 index 58db0ee..0000000 --- a/docs/yow/select.md +++ /dev/null @@ -1,42 +0,0 @@ ------------------------------------------------------------------------- - -# select - -Basis Function Combinator - -Use a Boolean value to select one of two items from a sequence. : - - [A B] false select - ------------------------ - A - - - [A B] true select - ----------------------- - B - -The sequence can contain more than two items but not fewer. Currently -Python semantics are used to evaluate the \"truthiness\" of the Boolean -value (so empty string, zero, etc. are counted as false, etc.) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/select.rst b/docs/yow/select.rst deleted file mode 100644 index 8420b3c..0000000 --- a/docs/yow/select.rst +++ /dev/null @@ -1,58 +0,0 @@ --------------- - -select -^^^^^^^^ - -Basis Function Combinator - - -Use a Boolean value to select one of two items from a sequence. -:: - - [A B] false select - ------------------------ - A - - - [A B] true select - ----------------------- - B - -The sequence can contain more than two items but not fewer. -Currently Python semantics are used to evaluate the "truthiness" of the -Boolean value (so empty string, zero, etc. are counted as false, etc.) - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/sharing.md b/docs/yow/sharing.md deleted file mode 100644 index 3fcc61b..0000000 --- a/docs/yow/sharing.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# sharing - -Basis Function Combinator - -Print redistribution information. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/sharing.rst b/docs/yow/sharing.rst deleted file mode 100644 index 7dc4e8b..0000000 --- a/docs/yow/sharing.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -sharing -^^^^^^^^^ - -Basis Function Combinator - -Print redistribution information. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/shift.md b/docs/yow/shift.md deleted file mode 100644 index 0d7bb36..0000000 --- a/docs/yow/shift.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# shift - -Basis Function Combinator - -uncons \[swons\] dip - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/shift.rst b/docs/yow/shift.rst deleted file mode 100644 index 82a481e..0000000 --- a/docs/yow/shift.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -shift -^^^^^^^ - -Basis Function Combinator - -uncons [swons] dip - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/shunt.md b/docs/yow/shunt.md deleted file mode 100644 index 81d3a1a..0000000 --- a/docs/yow/shunt.md +++ /dev/null @@ -1,35 +0,0 @@ ------------------------------------------------------------------------- - -# shunt - -Basis Function Combinator - -Like concat but reverses the top list into the second. : - - shunt == [swons] step == reverse swap concat - - [a b c] [d e f] shunt - --------------------------- - [f e d a b c] - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/shunt.rst b/docs/yow/shunt.rst deleted file mode 100644 index 2be27c0..0000000 --- a/docs/yow/shunt.rst +++ /dev/null @@ -1,52 +0,0 @@ --------------- - -shunt -^^^^^^^ - -Basis Function Combinator - - -Like concat but reverses the top list into the second. -:: - - shunt == [swons] step == reverse swap concat - - [a b c] [d e f] shunt - --------------------------- - [f e d a b c] - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/size.md b/docs/yow/size.md deleted file mode 100644 index 879796c..0000000 --- a/docs/yow/size.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# size - -Basis Function Combinator - -\[pop ++\] step_zero - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/size.rst b/docs/yow/size.rst deleted file mode 100644 index b49a40e..0000000 --- a/docs/yow/size.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -size -^^^^^^ - -Basis Function Combinator - -[pop ++] step_zero - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/sort.md b/docs/yow/sort.md deleted file mode 100644 index f3f6c61..0000000 --- a/docs/yow/sort.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# sort - -Basis Function Combinator - -Given a list return it sorted. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/sort.rst b/docs/yow/sort.rst deleted file mode 100644 index 85e0e13..0000000 --- a/docs/yow/sort.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -sort -^^^^^^ - -Basis Function Combinator - -Given a list return it sorted. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/spiral_next.md b/docs/yow/spiral_next.md deleted file mode 100644 index 54a6604..0000000 --- a/docs/yow/spiral_next.md +++ /dev/null @@ -1,31 +0,0 @@ ------------------------------------------------------------------------- - -# spiral_next - -Basis Function Combinator - -\[\[\[abs\] ii \<=\] \[\[\<\>\] \[pop !-\] \|\|\] &&\] \[\[!-\] -\[\[++\]\] \[\[\--\]\] ifte dip\] \[\[pop !-\] \[\--\] \[++\] ifte\] -ifte - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/spiral_next.rst b/docs/yow/spiral_next.rst deleted file mode 100644 index d860668..0000000 --- a/docs/yow/spiral_next.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -spiral_next -^^^^^^^^^^^^^ - -Basis Function Combinator - -[[[abs] ii <=] [[<>] [pop !-] ||] &&] [[!-] [[++]] [[--]] ifte dip] [[pop !-] [--] [++] ifte] ifte - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/split_at.md b/docs/yow/split_at.md deleted file mode 100644 index 6a79774..0000000 --- a/docs/yow/split_at.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# split_at - -Basis Function Combinator - -\[drop\] \[take\] clop - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/split_at.rst b/docs/yow/split_at.rst deleted file mode 100644 index 39b5fe4..0000000 --- a/docs/yow/split_at.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -split_at -^^^^^^^^^^ - -Basis Function Combinator - -[drop] [take] clop - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/split_list.md b/docs/yow/split_list.md deleted file mode 100644 index ce0bf06..0000000 --- a/docs/yow/split_list.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# split_list - -Basis Function Combinator - -\[take reverse\] \[drop\] clop - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/split_list.rst b/docs/yow/split_list.rst deleted file mode 100644 index fdf542b..0000000 --- a/docs/yow/split_list.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -split_list -^^^^^^^^^^^^ - -Basis Function Combinator - -[take reverse] [drop] clop - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/sqr.md b/docs/yow/sqr.md deleted file mode 100644 index e76cb20..0000000 --- a/docs/yow/sqr.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# sqr - -Basis Function Combinator - -dup \* - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/sqr.rst b/docs/yow/sqr.rst deleted file mode 100644 index af02e2a..0000000 --- a/docs/yow/sqr.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -sqr -^^^^^ - -Basis Function Combinator - -dup * - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/sqrt.md b/docs/yow/sqrt.md deleted file mode 100644 index ac4ce77..0000000 --- a/docs/yow/sqrt.md +++ /dev/null @@ -1,30 +0,0 @@ ------------------------------------------------------------------------- - -# sqrt - -Basis Function Combinator - -Return the square root of the number a. Negative numbers return complex -roots. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/sqrt.rst b/docs/yow/sqrt.rst deleted file mode 100644 index 93bf6fc..0000000 --- a/docs/yow/sqrt.rst +++ /dev/null @@ -1,45 +0,0 @@ --------------- - -sqrt -^^^^^^ - -Basis Function Combinator - - -Return the square root of the number a. -Negative numbers return complex roots. - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/stack.md b/docs/yow/stack.md deleted file mode 100644 index a39d524..0000000 --- a/docs/yow/stack.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# stack - -Basis Function Combinator - - (... -- ... [...]) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/stack.rst b/docs/yow/stack.rst deleted file mode 100644 index 809349f..0000000 --- a/docs/yow/stack.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -stack -^^^^^^^ - -Basis Function Combinator - - -:: - - (... -- ... [...]) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/stackd.md b/docs/yow/stackd.md deleted file mode 100644 index 5726f49..0000000 --- a/docs/yow/stackd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# stackd - -Basis Function Combinator - -\[stack\] dip - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/stackd.rst b/docs/yow/stackd.rst deleted file mode 100644 index 4d88bad..0000000 --- a/docs/yow/stackd.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -stackd -^^^^^^^^ - -Basis Function Combinator - -[stack] dip - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/step.md b/docs/yow/step.md deleted file mode 100644 index 9220722..0000000 --- a/docs/yow/step.md +++ /dev/null @@ -1,46 +0,0 @@ ------------------------------------------------------------------------- - -# step - -Basis Function Combinator - -Run a quoted program on each item in a sequence. : - - ... [] [Q] . step - ----------------------- - ... . - - - ... [a] [Q] . step - ------------------------ - ... a . Q - - - ... [a b c] [Q] . step - ---------------------------------------- - ... a . Q [b c] [Q] step - -The step combinator executes the quotation on each member of the list on -top of the stack. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/step.rst b/docs/yow/step.rst deleted file mode 100644 index 6cd485b..0000000 --- a/docs/yow/step.rst +++ /dev/null @@ -1,62 +0,0 @@ --------------- - -step -^^^^^^ - -Basis Function Combinator - - -Run a quoted program on each item in a sequence. -:: - - ... [] [Q] . step - ----------------------- - ... . - - - ... [a] [Q] . step - ------------------------ - ... a . Q - - - ... [a b c] [Q] . step - ---------------------------------------- - ... a . Q [b c] [Q] step - -The step combinator executes the quotation on each member of the list -on top of the stack. - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/step_zero.md b/docs/yow/step_zero.md deleted file mode 100644 index 26da9e9..0000000 --- a/docs/yow/step_zero.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# step_zero - -Basis Function Combinator - -0 roll> step - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/step_zero.rst b/docs/yow/step_zero.rst deleted file mode 100644 index b8d5c3e..0000000 --- a/docs/yow/step_zero.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -step_zero -^^^^^^^^^^^ - -Basis Function Combinator - -0 roll> step - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/stuncons.md b/docs/yow/stuncons.md deleted file mode 100644 index a02c46e..0000000 --- a/docs/yow/stuncons.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# stuncons - -Basis Function Combinator - - (... a1 -- ... a1 a1 [...]) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/stuncons.rst b/docs/yow/stuncons.rst deleted file mode 100644 index b735b95..0000000 --- a/docs/yow/stuncons.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -stuncons -^^^^^^^^^^ - -Basis Function Combinator - - -:: - - (... a1 -- ... a1 a1 [...]) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/stununcons.md b/docs/yow/stununcons.md deleted file mode 100644 index 7fbe80d..0000000 --- a/docs/yow/stununcons.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# stununcons - -Basis Function Combinator - - (... a2 a1 -- ... a2 a1 a1 a2 [...]) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/stununcons.rst b/docs/yow/stununcons.rst deleted file mode 100644 index e5c055f..0000000 --- a/docs/yow/stununcons.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -stununcons -^^^^^^^^^^^^ - -Basis Function Combinator - - -:: - - (... a2 a1 -- ... a2 a1 a1 a2 [...]) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/sub.md b/docs/yow/sub.md deleted file mode 100644 index 86eb7d6..0000000 --- a/docs/yow/sub.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# sub - -Basis Function Combinator - -Same as a - b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/sub.rst b/docs/yow/sub.rst deleted file mode 100644 index c52dccb..0000000 --- a/docs/yow/sub.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -sub -^^^^^ - -Basis Function Combinator - -Same as a - b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/succ.md b/docs/yow/succ.md deleted file mode 100644 index c8aeb94..0000000 --- a/docs/yow/succ.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# succ - -Basis Function Combinator - -Increment TOS. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/succ.rst b/docs/yow/succ.rst deleted file mode 100644 index 93d03b4..0000000 --- a/docs/yow/succ.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -succ -^^^^^^ - -Basis Function Combinator - -Increment TOS. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/sum.md b/docs/yow/sum.md deleted file mode 100644 index b1f87b6..0000000 --- a/docs/yow/sum.md +++ /dev/null @@ -1,31 +0,0 @@ ------------------------------------------------------------------------- - -# sum - -Basis Function Combinator - -Given a quoted sequence of numbers return the sum. : - - sum == 0 swap [+] step - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/sum.rst b/docs/yow/sum.rst deleted file mode 100644 index 5cc2d70..0000000 --- a/docs/yow/sum.rst +++ /dev/null @@ -1,48 +0,0 @@ --------------- - -sum -^^^^^ - -Basis Function Combinator - - -Given a quoted sequence of numbers return the sum. -:: - - sum == 0 swap [+] step - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/swaack.md b/docs/yow/swaack.md deleted file mode 100644 index 7f68aef..0000000 --- a/docs/yow/swaack.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# swaack - -Basis Function Combinator - - ([...1] -- [...0]) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/swaack.rst b/docs/yow/swaack.rst deleted file mode 100644 index cd286eb..0000000 --- a/docs/yow/swaack.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -swaack -^^^^^^^^ - -Basis Function Combinator - - -:: - - ([...1] -- [...0]) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/swap.md b/docs/yow/swap.md deleted file mode 100644 index dd19579..0000000 --- a/docs/yow/swap.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# swap - -Basis Function Combinator - - (a1 a2 -- a2 a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/swap.rst b/docs/yow/swap.rst deleted file mode 100644 index 7ed54e3..0000000 --- a/docs/yow/swap.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -swap -^^^^^^ - -Basis Function Combinator - - -:: - - (a1 a2 -- a2 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/swapd.md b/docs/yow/swapd.md deleted file mode 100644 index a086f01..0000000 --- a/docs/yow/swapd.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# swapd - -Basis Function Combinator - -\[swap\] dip - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/swapd.rst b/docs/yow/swapd.rst deleted file mode 100644 index aa3a3dd..0000000 --- a/docs/yow/swapd.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -swapd -^^^^^^^ - -Basis Function Combinator - -[swap] dip - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/swoncat.md b/docs/yow/swoncat.md deleted file mode 100644 index cd1027d..0000000 --- a/docs/yow/swoncat.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# swoncat - -Basis Function Combinator - -swap concat - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/swoncat.rst b/docs/yow/swoncat.rst deleted file mode 100644 index 3921bf8..0000000 --- a/docs/yow/swoncat.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -swoncat -^^^^^^^^^ - -Basis Function Combinator - -swap concat - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/swons.md b/docs/yow/swons.md deleted file mode 100644 index e3ccafe..0000000 --- a/docs/yow/swons.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# swons - -Basis Function Combinator - - ([...1] a1 -- [a1 ...1]) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/swons.rst b/docs/yow/swons.rst deleted file mode 100644 index fb8ac9a..0000000 --- a/docs/yow/swons.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -swons -^^^^^^^ - -Basis Function Combinator - - -:: - - ([...1] a1 -- [a1 ...1]) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/tailrec.md b/docs/yow/tailrec.md deleted file mode 100644 index 82e0dd8..0000000 --- a/docs/yow/tailrec.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# tailrec - -Basis Function Combinator - -\[i\] genrec - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/tailrec.rst b/docs/yow/tailrec.rst deleted file mode 100644 index 92ddcfd..0000000 --- a/docs/yow/tailrec.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -tailrec -^^^^^^^^^ - -Basis Function Combinator - -[i] genrec - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/take.md b/docs/yow/take.md deleted file mode 100644 index 951dcf3..0000000 --- a/docs/yow/take.md +++ /dev/null @@ -1,35 +0,0 @@ ------------------------------------------------------------------------- - -# take - -Basis Function Combinator - -Expects an integer and a quote on the stack and returns the quote with -just the top n items in reverse order (because that\'s easier and you -can use reverse if needed.) : - - [a b c d] 2 take - ---------------------- - [b a] - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/take.rst b/docs/yow/take.rst deleted file mode 100644 index 42c2053..0000000 --- a/docs/yow/take.rst +++ /dev/null @@ -1,52 +0,0 @@ --------------- - -take -^^^^^^ - -Basis Function Combinator - - -Expects an integer and a quote on the stack and returns the quote with -just the top n items in reverse order (because that's easier and you can -use reverse if needed.) -:: - - [a b c d] 2 take - ---------------------- - [b a] - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/third.md b/docs/yow/third.md deleted file mode 100644 index 32bd760..0000000 --- a/docs/yow/third.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# third - -Basis Function Combinator - - ([a1 a2 a3 ...1] -- a3) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/third.rst b/docs/yow/third.rst deleted file mode 100644 index 2f25e7b..0000000 --- a/docs/yow/third.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -third -^^^^^^^ - -Basis Function Combinator - - -:: - - ([a1 a2 a3 ...1] -- a3) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/times.md b/docs/yow/times.md deleted file mode 100644 index 5bb6cf9..0000000 --- a/docs/yow/times.md +++ /dev/null @@ -1,43 +0,0 @@ ------------------------------------------------------------------------- - -# times - -Basis Function Combinator - -times == \[\-- dip\] cons \[swap\] infra \[0 \>\] swap while pop : - - ... n [Q] . times - --------------------- w/ n <= 0 - ... . - - - ... 1 [Q] . times - ----------------------- - ... . Q - - - ... n [Q] . times - ------------------------------------- w/ n > 1 - ... . Q (n - 1) [Q] times - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/times.rst b/docs/yow/times.rst deleted file mode 100644 index a66e335..0000000 --- a/docs/yow/times.rst +++ /dev/null @@ -1,60 +0,0 @@ --------------- - -times -^^^^^^^ - -Basis Function Combinator - - -times == [-- dip] cons [swap] infra [0 >] swap while pop -:: - - ... n [Q] . times - --------------------- w/ n <= 0 - ... . - - - ... 1 [Q] . times - ----------------------- - ... . Q - - - ... n [Q] . times - ------------------------------------- w/ n > 1 - ... . Q (n - 1) [Q] times - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/truthy.md b/docs/yow/truthy.md deleted file mode 100644 index 23aa6a5..0000000 --- a/docs/yow/truthy.md +++ /dev/null @@ -1,6 +0,0 @@ --------------- - -# truthy - -See [bool](#bool). - diff --git a/docs/yow/truthy.rst b/docs/yow/truthy.rst deleted file mode 100644 index a93f7fb..0000000 --- a/docs/yow/truthy.rst +++ /dev/null @@ -1,46 +0,0 @@ --------------- - -truthy -^^^^^^^^ - -Basis Function Combinator - -bool(x) -> bool - -Returns True when the argument x is true, False otherwise. -The builtins True and False are the only two instances of the class bool. -The class bool is a subclass of the class int, and cannot be subclassed. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/tuck.md b/docs/yow/tuck.md deleted file mode 100644 index 6288117..0000000 --- a/docs/yow/tuck.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# tuck - -Basis Function Combinator - - (a2 a1 -- a1 a2 a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/tuck.rst b/docs/yow/tuck.rst deleted file mode 100644 index 558b871..0000000 --- a/docs/yow/tuck.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -tuck -^^^^^^ - -Basis Function Combinator - - -:: - - (a2 a1 -- a1 a2 a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/unique.md b/docs/yow/unique.md deleted file mode 100644 index a0a324d..0000000 --- a/docs/yow/unique.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# unique - -Basis Function Combinator - -Given a list remove duplicate items. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/unique.rst b/docs/yow/unique.rst deleted file mode 100644 index 7feef04..0000000 --- a/docs/yow/unique.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -unique -^^^^^^^^ - -Basis Function Combinator - -Given a list remove duplicate items. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/unit.md b/docs/yow/unit.md deleted file mode 100644 index 1761e9e..0000000 --- a/docs/yow/unit.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# unit - -Basis Function Combinator - - (a1 -- [a1 ]) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/unit.rst b/docs/yow/unit.rst deleted file mode 100644 index 0249efd..0000000 --- a/docs/yow/unit.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -unit -^^^^^^ - -Basis Function Combinator - - -:: - - (a1 -- [a1 ]) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/unquoted.md b/docs/yow/unquoted.md deleted file mode 100644 index 65cea66..0000000 --- a/docs/yow/unquoted.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# unquoted - -Basis Function Combinator - -\[i\] dip - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/unquoted.rst b/docs/yow/unquoted.rst deleted file mode 100644 index 832c943..0000000 --- a/docs/yow/unquoted.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -unquoted -^^^^^^^^^^ - -Basis Function Combinator - -[i] dip - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/unswons.md b/docs/yow/unswons.md deleted file mode 100644 index ca87303..0000000 --- a/docs/yow/unswons.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# unswons - -Basis Function Combinator - - ([a1 ...1] -- [...1] a1) - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/unswons.rst b/docs/yow/unswons.rst deleted file mode 100644 index e96d786..0000000 --- a/docs/yow/unswons.rst +++ /dev/null @@ -1,47 +0,0 @@ --------------- - -unswons -^^^^^^^^^ - -Basis Function Combinator - - -:: - - ([a1 ...1] -- [...1] a1) - - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/void.md b/docs/yow/void.md deleted file mode 100644 index 02f3511..0000000 --- a/docs/yow/void.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# void - -Basis Function Combinator - -True if the form on TOS is void otherwise False. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/void.rst b/docs/yow/void.rst deleted file mode 100644 index c116d34..0000000 --- a/docs/yow/void.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -void -^^^^^^ - -Basis Function Combinator - -True if the form on TOS is void otherwise False. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/warranty.md b/docs/yow/warranty.md deleted file mode 100644 index 3aaab41..0000000 --- a/docs/yow/warranty.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# warranty - -Basis Function Combinator - -Print warranty information. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/warranty.rst b/docs/yow/warranty.rst deleted file mode 100644 index 2a783c2..0000000 --- a/docs/yow/warranty.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -warranty -^^^^^^^^^^ - -Basis Function Combinator - -Print warranty information. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/while.md b/docs/yow/while.md deleted file mode 100644 index a7190da..0000000 --- a/docs/yow/while.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# while - -Basis Function Combinator - -swap nulco dupdipd concat loop - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/while.rst b/docs/yow/while.rst deleted file mode 100644 index 6cc9759..0000000 --- a/docs/yow/while.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -while -^^^^^^^ - -Basis Function Combinator - -swap nulco dupdipd concat loop - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/words.md b/docs/yow/words.md deleted file mode 100644 index 59c6ada..0000000 --- a/docs/yow/words.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# words - -Basis Function Combinator - -Print all the words in alphabetical order. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/words.rst b/docs/yow/words.rst deleted file mode 100644 index 282b775..0000000 --- a/docs/yow/words.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -words -^^^^^^^ - -Basis Function Combinator - -Print all the words in alphabetical order. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/wrods.py b/docs/yow/wrods.py deleted file mode 100644 index a1d0b1a..0000000 --- a/docs/yow/wrods.py +++ /dev/null @@ -1,127 +0,0 @@ -''' -A brutal little script to rip out the ReST docstrings and emit -ReST files for Pandoc to transform into Markdown. - -This is a one-off script. - -''' -from pathlib import Path -from string import ascii_letters, digits -from textwrap import dedent -from unicodedata import name - -from joy.library import initialize, default_defs - - -refdir = Path('../reference') -okay = set(ascii_letters + digits + '_') - -# Initialize the Joy dictionary. -D = initialize() -default_defs(D) - -words = sorted( - name - for name in D - if not name.startswith('_') - ) - -# words = '!- != % & && * + ++ - -- / // /floor < << <<{} <= <> <{} = > >= >> ? ^ _Tree_add_Ee _Tree_delete_R0 _Tree_delete_clear_stuff _Tree_get_E _map0 _map1 _map2 _map? _mape _step0 _step1 _stept _times0 _times1 _timest abs add anamorphism and app1 app2 app3 appN at average b binary bool branch ccccons ccons choice clear cleave clop cmp codi codireco concat cond cons dinfrirst dip dipd dipdd disenstacken div divmod down_to_zero drop dup dupd dupdd dupdip dupdipd enstacken eq first first_two flatten floor floordiv fork fourth gcd gcd2 ge genrec getitem grabN grba gt help hypot i id ifte ii infra infrst inscribe le loop lshift lt make_generator map max min mod modulus mul ne neg not nulco nullary of or over pam pick pm pop popd popdd popop popopd popopdd popopop pow pred primrec product quoted range range_to_zero reco rem remainder remove rest reverse roll< roll> rolldown rollup round rrest rshift run second select sharing shift shunt size sort spiral_next split_at split_list sqr sqrt stack stackd step step_zero stuncons stununcons sub succ sum swaack swap swapd swoncat swons tailrec take ternary third times trace truthy tuck unary uncons unique unit unquoted unswons void warranty while words x xor zip || •'.split() - - -def units_of_filename(fn): - unit = '' - for char in fn: - if char not in okay: - if unit: - yield unit - unit = '' - yield name(char).replace(' ', '-') - else: - unit += char - if unit: - yield unit - - -def safe_filename(fn): - return '•'.join(units_of_filename(fn)) - -done_manually = '''\ -app1.md -b.md -binary.md -ccons.md -cons.md -i.md -infra.md -nullary.md -ternary.md -unary.md -uncons.md -x.md'''.split() - -for w in words: - - ww = safe_filename(w) - rst = f'{ww}.rst' - - fn = f'{w}.md' - if fn in done_manually: - continue - -## rf = (refdir / fn) -## if rf.exists(): -## print(f'copying existing {fn}') -## Path(fn).write_bytes(rf.read_bytes()) -## continue - - Path(rst).write_text(f'''\ --------------- - -{w} -{'^' * (len(w) + 2)} - -Basis Function Combinator - -{dedent(D[w].__doc__)} - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - -''', encoding='UTF_8') - - -## ww = w.replace('/', '∕') # U+2215 ∕ DIVISION SLASH -## Path(rst).touch() -## print(D[w].__doc__) - diff --git a/docs/yow/xor.md b/docs/yow/xor.md deleted file mode 100644 index c9e948a..0000000 --- a/docs/yow/xor.md +++ /dev/null @@ -1,29 +0,0 @@ ------------------------------------------------------------------------- - -# xor - -Basis Function Combinator - -Same as a \^ b. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/xor.rst b/docs/yow/xor.rst deleted file mode 100644 index 44628f3..0000000 --- a/docs/yow/xor.rst +++ /dev/null @@ -1,42 +0,0 @@ --------------- - -xor -^^^^^ - -Basis Function Combinator - -Same as a ^ b. - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/docs/yow/zip.md b/docs/yow/zip.md deleted file mode 100644 index e54cb2e..0000000 --- a/docs/yow/zip.md +++ /dev/null @@ -1,30 +0,0 @@ ------------------------------------------------------------------------- - -# zip - -Basis Function Combinator - -Replace the two lists on the top of the stack with a list of the pairs -from each list. The smallest list sets the length of the result list. - -Gentzen diagram. - -## Definition - -if not basis. - -## Derivation - -if not basis. - -## Source - -if basis - -## Discussion - -Lorem ipsum. - -## Crosslinks - -Lorem ipsum. diff --git a/docs/yow/zip.rst b/docs/yow/zip.rst deleted file mode 100644 index f450c5f..0000000 --- a/docs/yow/zip.rst +++ /dev/null @@ -1,45 +0,0 @@ --------------- - -zip -^^^^^ - -Basis Function Combinator - - -Replace the two lists on the top of the stack with a list of the pairs -from each list. The smallest list sets the length of the result list. - - -Gentzen diagram. - - -Definition -~~~~~~~~~~ - -if not basis. - - -Derivation -~~~~~~~~~~ - -if not basis. - - -Source -~~~~~~~~~~ - -if basis - - -Discussion -~~~~~~~~~~ - -Lorem ipsum. - - -Crosslinks -~~~~~~~~~~ - -Lorem ipsum. - - diff --git a/implementations/expr.py b/implementations/expr.py deleted file mode 100644 index a078d43..0000000 --- a/implementations/expr.py +++ /dev/null @@ -1,118 +0,0 @@ -from itertools import chain -from joy.utils.stack import _s, iter_stack - - - -# Expression as a stack-of-stacks - -def push_term(quote, expression): - ''' - Put the quoted program onto the stack-of-stacks. - ''' - return (quote, expression) if quote else expression - -def next_term(expression): - ''' - Return the next term from the expression and the new expression. - ''' - # Don't call this with an () expression. - assert expression, repr(expression) - - quote, expression = expression - - # If you're using prepend() an empty quote can never get onto the - # expression. - assert quote, repr(quote) - - item, quote = quote - if quote: - # Put the rest of the quote back onto the stack-of-stacks. - expression = quote, expression - - return item, expression - - - - -class Expression: - ''' - As elegant as it is to model the expression as a stack, it's not very - efficient, as concatenating definitions and other quoted programs to - the expression is a common and expensive operation. - - Instead, let's keep a stack of sub-expressions, reading from them - one-by-one, and prepending new sub-expressions to the stack rather than - concatenating them. - ''' - - def __init__(self, initial_expression=()): - self.current = initial_expression - self.stack = [] - - def __iter__(self): - return self - - def __next__(self): - if self.current: (item, self.current) = self.current - elif self.stack: (item, self.current) = self.stack.pop() - else: raise StopIteration - return item - - def prepend(self, quoted_program): - if not quoted_program: return - if self.current: self.stack.append(self.current) - self.current = quoted_program - - def __bool__(self): - return bool(self.current or self.stack) - - def __str__(self): - return ' '.join( - map( - _s, - chain.from_iterable( - map( - iter_stack, - reversed(self.stack + [self.current]) - ) - ) - ) - ) - - -class E(Expression): - - def __iter__(self): - return iter((self.__next__(), self)) - - -if __name__ == '__main__': - from joy.parser import text_to_expression as j - - e = Expression(j('23 18')) - e.prepend(j('88 19')) - e.prepend(j('foo fie feum')) - print(e) - for i in e: - print(i, e.stack, e.current) - if i == 88: - print('prepending "hello world"') - e.prepend(j('hello world')) - if i == 19: - print('prepending "good bye"') - e.prepend(j('good bye')) - print('-'*20) - e = E(j('23 18')) - e.prepend(j('88 19')) - e.prepend(j('foo fie feum')) - print(e) - while e: - i, e = e - print(i, e.stack, e.current) - if i == 88: - print('prepending "hello world"') - e.prepend(j('hello world')) - if i == 19: - print('prepending "good bye"') - e.prepend(j('good bye')) -