diff --git a/.hgignore b/.hgignore index 2bf58da..0276843 100644 --- a/.hgignore +++ b/.hgignore @@ -3,4 +3,5 @@ build .hypothesis .pytest_cache .vscode +docs/.ipynb_checkpoints diff --git a/docs/4. Replacing Functions in the Dictionary.ipynb b/docs/4. Replacing Functions in the Dictionary.ipynb index 598d697..16cfeb7 100644 --- a/docs/4. Replacing Functions in the Dictionary.ipynb +++ b/docs/4. Replacing Functions in the Dictionary.ipynb @@ -244,7 +244,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.13" + "version": "2.7.12" } }, "nbformat": 4, diff --git a/docs/Generator Programs.ipynb b/docs/Generator Programs.ipynb index d202481..0ed86be 100644 --- a/docs/Generator Programs.ipynb +++ b/docs/Generator Programs.ipynb @@ -22,29 +22,56 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Consider the `x` combinator `x == dup i`:\n", + "Consider the `x` combinator:\n", + "\n", + " x == dup i\n", + "\n", + "We can apply it to a quoted program consisting of some value `a` and a function `B`:\n", "\n", " [a B] x\n", - " [a B] a B\n", + " [a B] a B" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let `B` function `swap` the `a` with the quote and run some function `C` on it to generate a new value `b`:\n", "\n", - "Let `B` `swap` the `a` with the quote and run some function `[C]` on it.\n", + " B == swap [C] dip\n", "\n", " [a B] a B\n", " [a B] a swap [C] dip\n", " a [a B] [C] dip\n", " a C [a B]\n", + " b [a B]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now discard the quoted `a` with `rest` then `cons` `b`:\n", "\n", - "Now discard the quoted `a` with `rest` and `cons` the result of `C` on `a` whatever that is:\n", + " b [a B] rest cons\n", + " b [B] cons\n", + " [b B]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Putting it together, this is the definition of `B`:\n", "\n", - " aC [a B] rest cons\n", - " aC [B] cons\n", - " [aC B]\n", - "\n", - "Altogether, this is the definition of `B`:\n", - "\n", - " B == swap [C] dip rest cons\n", - "\n", - "We can create a quoted program that generates the Natural numbers (integers 0, 1, 2, ...) by using `0` for `a` and `[dup ++]` for `[C]`:\n", + " B == swap [C] dip rest cons" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can create a quoted program that generates the Natural numbers (0, 1, 2, ...) by using `0` for `a` and `[dup ++]` for `[C]`:\n", "\n", " [0 swap [dup ++] dip rest cons]\n", "\n", @@ -154,15 +181,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Generating Generators\n", - "We want to go from:\n", - "\n", - " a [C] G\n", - "\n", - "to:\n", - "\n", - " [a swap [C] direco]\n", + "# Making Generators\n", + "We want to define a function that accepts `a` and `[C]` and builds our quoted program:\n", "\n", + " a [C] G\n", + " -------------------------\n", + " [a swap [C] direco]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "Working in reverse:\n", "\n", " [a swap [C] direco] cons\n", @@ -174,11 +204,7 @@ "Reading from the bottom up:\n", "\n", " G == [direco] cons [swap] swap concat cons\n", - " G == [direco] cons [swap] swoncat cons\n", - "\n", - "We can try it out:\n", - "\n", - " 0 [dup ++] G" + " G == [direco] cons [swap] swoncat cons" ] }, { @@ -190,6 +216,13 @@ "define('G == [direco] cons [swap] swoncat cons')" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's try it out:" + ] + }, { "cell_type": "code", "execution_count": 7, @@ -199,22 +232,12 @@ "name": "stdout", "output_type": "stream", "text": [ - " . 0 [dup ++] G\n", - " 0 . [dup ++] G\n", - " 0 [dup ++] . G\n", - " 0 [dup ++] . [direco] cons [swap] swoncat cons\n", - " 0 [dup ++] [direco] . cons [swap] swoncat cons\n", - " 0 [[dup ++] direco] . [swap] swoncat cons\n", - "0 [[dup ++] direco] [swap] . swoncat cons\n", - "0 [[dup ++] direco] [swap] . swap concat cons\n", - "0 [swap] [[dup ++] direco] . concat cons\n", - " 0 [swap [dup ++] direco] . cons\n", - " [0 swap [dup ++] direco] . \n" + "[0 swap [dup ++] direco]\n" ] } ], "source": [ - "V('0 [dup ++] G')" + "J('0 [dup ++] G')" ] }, { @@ -226,33 +249,12 @@ "name": "stdout", "output_type": "stream", "text": [ - " . 0 [dup ++] G x\n", - " 0 . [dup ++] G x\n", - " 0 [dup ++] . G x\n", - " 0 [dup ++] . [direco] cons [swap] swoncat cons x\n", - " 0 [dup ++] [direco] . cons [swap] swoncat cons x\n", - " 0 [[dup ++] direco] . [swap] swoncat cons x\n", - " 0 [[dup ++] direco] [swap] . swoncat cons x\n", - " 0 [[dup ++] direco] [swap] . swap concat cons x\n", - " 0 [swap] [[dup ++] direco] . concat cons x\n", - " 0 [swap [dup ++] direco] . cons x\n", - " [0 swap [dup ++] direco] . x\n", - " [0 swap [dup ++] direco] . 0 swap [dup ++] direco\n", - " [0 swap [dup ++] direco] 0 . swap [dup ++] direco\n", - " 0 [0 swap [dup ++] direco] . [dup ++] direco\n", - "0 [0 swap [dup ++] direco] [dup ++] . direco\n", - "0 [0 swap [dup ++] direco] [dup ++] . dip rest cons\n", - " 0 . dup ++ [0 swap [dup ++] direco] rest cons\n", - " 0 0 . ++ [0 swap [dup ++] direco] rest cons\n", - " 0 1 . [0 swap [dup ++] direco] rest cons\n", - " 0 1 [0 swap [dup ++] direco] . rest cons\n", - " 0 1 [swap [dup ++] direco] . cons\n", - " 0 [1 swap [dup ++] direco] . \n" + "0 1 2\n" ] } ], "source": [ - "V('0 [dup ++] G x')" + "J('0 [dup ++] G x x x pop')" ] }, { @@ -271,22 +273,20 @@ "name": "stdout", "output_type": "stream", "text": [ - "1 2 4 8 16 32 64 128 256 [512 swap [dup 1 <<] direco]\n" + "1 2 4 8 16 32 64 128 256\n" ] } ], "source": [ - "J('1 [dup 1 <<] G x x x x x x x x x')" + "J('1 [dup 1 <<] G x x x x x x x x x pop')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# `n [x] times`\n", - "If we have one of these quoted programs we can drive it using `times` with the `x` combinator.\n", - "\n", - "Let's define a word `n_range` that takes a starting integer and a count and leaves that many consecutive integers on the stack. For example:" + "### `[x] times`\n", + "If we have one of these quoted programs we can drive it using `times` with the `x` combinator." ] }, { @@ -298,95 +298,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "23 24 25 26 27\n" + "23 24 25 26 27 [28 swap [dup ++] direco]\n" ] } ], "source": [ - "J('23 [dup ++] G 5 [x] times pop')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can use `dip` to untangle `[dup ++] G` from the arguments." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "23 24 25 26 27\n" - ] - } - ], - "source": [ - "J('23 5 [[dup ++] G] dip [x] times pop')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that the givens (arguments) are on the left we have the definition we're looking for:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "define('n_range == [[dup ++] G] dip [x] times pop')" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "450 451 452 453 454 455 456 457 458 459\n" - ] - } - ], - "source": [ - "J('450 10 n_range')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is better just using the `times` combinator though..." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "450 451 452 453 454 455 456 457 458 459\n" - ] - } - ], - "source": [ - "J('450 9 [dup ++] times')" + "J('23 [dup ++] G 5 [x] times')" ] }, { @@ -408,7 +325,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -417,7 +334,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -451,7 +368,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 13, "metadata": {}, "outputs": [ { @@ -466,23 +383,6 @@ "J('14811 [PE1.1] G')" ] }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3 [3702 swap [PE1.1] direco]\n" - ] - } - ], - "source": [ - "J('[14811 swap [PE1.1] direco] x')" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -492,7 +392,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 14, "metadata": { "scrolled": true }, @@ -519,7 +419,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -528,7 +428,24 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[14811 swap [PE1.1.check PE1.1] direco]\n" + ] + } + ], + "source": [ + "J('14811 [PE1.1.check PE1.1] G')" + ] + }, + { + "cell_type": "code", + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -543,6 +460,13 @@ "J('[14811 swap [PE1.1.check PE1.1] direco] 21 [x] times')" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(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.)" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -553,7 +477,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 18, "metadata": {}, "outputs": [ { @@ -577,7 +501,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 19, "metadata": { "scrolled": false }, @@ -586,17 +510,17 @@ "name": "stdout", "output_type": "stream", "text": [ - "3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 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] dip rest cons]\n" + "3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 2 1 3 1 2 3 3 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]\n" ] } ], "source": [ - "J('[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times')" + "J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times')" ] }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 20, "metadata": { "scrolled": true }, @@ -610,7 +534,7 @@ } ], "source": [ - "J('[14811 swap [PE1.1.check PE1.1] dip rest cons] 466 [x] times pop enstacken sum')" + "J('[14811 swap [PE1.1.check PE1.1] direco] 466 [x] times pop enstacken sum')" ] }, { @@ -622,7 +546,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -633,36 +557,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now we can add `PE1.2` to the quoted program given to `times`." + "Now we can add `PE1.2` to the quoted program given to `G`." ] }, { "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "233168\n" - ] - } - ], - "source": [ - "J('0 0 [0 swap [PE1.1.check PE1.1] direco] 466 [x [PE1.2] dip] times popop')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Or using `G` we can write:" - ] - }, - { - "cell_type": "code", - "execution_count": 27, + "execution_count": 22, "metadata": {}, "outputs": [ { @@ -685,68 +585,119 @@ "Consider:\n", "\n", " [b a F] x\n", - " [b a F] b a F\n", - "\n", + " [b a F] b a F" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "The obvious first thing to do is just add `b` and `a`:\n", "\n", " [b a F] b a +\n", - " [b a F] b+a\n", - "\n", + " [b a F] b+a" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "From here we want to arrive at:\n", "\n", - " b [b+a b F]\n", - "\n", + " b [b+a b F]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "Let's start with `swons`:\n", "\n", " [b a F] b+a swons\n", - " [b+a b a F]\n", - "\n", + " [b+a b a F]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "Considering this quote as a stack:\n", "\n", - " F a b b+a\n", - "\n", + " F a b b+a" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "We want to get it to:\n", "\n", - " F b b+a b\n", - "\n", + " F b b+a b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "So:\n", "\n", " F a b b+a popdd over\n", - " F b b+a b\n", - "\n", + " F b b+a b" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "And therefore:\n", "\n", " [b+a b a F] [popdd over] infra\n", - " [b b+a b F]\n", + " [b b+a b F]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But we can just use `cons` to carry `b+a` into the quote:\n", "\n", - "And lastly:\n", + " [b a F] b+a [popdd over] cons infra\n", + " [b a F] [b+a popdd over] infra\n", + " [b b+a b F]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lastly:\n", "\n", " [b b+a b F] uncons\n", - " b [b+a b F]\n", - "\n", - "Done.\n", - "\n", + " b [b+a b F]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "Putting it all together:\n", "\n", - " F == + swons [popdd over] infra uncons\n", - "\n", - "And:\n", - "\n", + " F == + [popdd over] cons infra uncons\n", " fib_gen == [1 1 F]" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 23, "metadata": {}, "outputs": [], "source": [ - "define('fib == + swons [popdd over] infra uncons')" + "define('fib == + [popdd over] cons infra uncons')" ] }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -755,7 +706,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 25, "metadata": {}, "outputs": [ { @@ -775,14 +726,15 @@ "metadata": {}, "source": [ "### Project Euler Problem Two\n", - " By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.\n", + " By considering the terms in the Fibonacci sequence whose values do not exceed four million,\n", + " find the sum of the even-valued terms.\n", "\n", "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." ] }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -798,7 +750,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -814,7 +766,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ @@ -823,7 +775,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 29, "metadata": {}, "outputs": [ { @@ -876,7 +828,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 30, "metadata": {}, "outputs": [ { @@ -900,7 +852,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 31, "metadata": {}, "outputs": [ { @@ -917,7 +869,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 32, "metadata": {}, "outputs": [], "source": [ @@ -926,7 +878,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 33, "metadata": {}, "outputs": [ { @@ -950,7 +902,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 34, "metadata": {}, "outputs": [ { @@ -972,6 +924,78 @@ "# How to compile these?\n", "You would probably start with a special version of `G`, and perhaps modifications to the default `x`?" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# An Interesting Variation" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "define('codireco == cons dip rest cons')" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " . [0 [dup ++] codireco] x\n", + " [0 [dup ++] codireco] . x\n", + " [0 [dup ++] codireco] . 0 [dup ++] codireco\n", + " [0 [dup ++] codireco] 0 . [dup ++] codireco\n", + "[0 [dup ++] codireco] 0 [dup ++] . codireco\n", + "[0 [dup ++] codireco] 0 [dup ++] . cons dip rest cons\n", + "[0 [dup ++] codireco] [0 dup ++] . dip rest cons\n", + " . 0 dup ++ [0 [dup ++] codireco] rest cons\n", + " 0 . dup ++ [0 [dup ++] codireco] rest cons\n", + " 0 0 . ++ [0 [dup ++] codireco] rest cons\n", + " 0 1 . [0 [dup ++] codireco] rest cons\n", + " 0 1 [0 [dup ++] codireco] . rest cons\n", + " 0 1 [[dup ++] codireco] . cons\n", + " 0 [1 [dup ++] codireco] . \n" + ] + } + ], + "source": [ + "V('[0 [dup ++] codireco] x')" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "define('G == [codireco] cons cons')" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "230 231 232 233 234\n" + ] + } + ], + "source": [ + "J('230 [dup ++] G 5 [x] times pop')" + ] } ], "metadata": { @@ -990,7 +1014,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.13" + "version": "2.7.12" } }, "nbformat": 4, diff --git a/docs/Hylo-, Ana-, Cata-, and Para-morphisms - Recursion Combinators.ipynb b/docs/Hylo-, Ana-, Cata-, and Para-morphisms - Recursion Combinators.ipynb index 2d58dd0..fde17ad 100644 --- a/docs/Hylo-, Ana-, Cata-, and Para-morphisms - Recursion Combinators.ipynb +++ b/docs/Hylo-, Ana-, Cata-, and Para-morphisms - Recursion Combinators.ipynb @@ -1694,7 +1694,7 @@ "- A base case value `c :: B`\n", "\n", "\n", - "### Hylo- Ana-, Cata-\n", + "### Hylo-, Ana-, Cata-\n", "\n", " w/ G :: A -> (A, B)\n", "\n", @@ -1812,7 +1812,7 @@ "metadata": {}, "source": [ "### 4\n", - "And, last but not least, if you can combine as you go, starting with c, and the combiner needs to work on the current item this is the form:\n", + "And, last but not least, if you can combine as you go, starting with c, and the combiner needs to work on the current item, this is the form:\n", "\n", " W == c swap [P] [pop] [[F] dupdip G] primrec\n", "\n", diff --git a/docs/Quadratic.ipynb b/docs/Quadratic.ipynb index 9ba1208..89029f1 100644 --- a/docs/Quadratic.ipynb +++ b/docs/Quadratic.ipynb @@ -267,7 +267,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.13" + "version": "2.7.12" } }, "nbformat": 4, diff --git a/docs/Treestep.ipynb b/docs/Treestep.ipynb index 93c3b79..6eb1c5e 100644 --- a/docs/Treestep.ipynb +++ b/docs/Treestep.ipynb @@ -15,31 +15,20 @@ "metadata": {}, "source": [ "## `treestep`\n", - "In the spirit of `step` we are going to define a combinator `treestep` which expects a tree and three additional items: a base-case value `z`, and two quoted programs `[N]` and `[C]`.\n", + "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]`.\n", "\n", - " tree z [N] [C] treestep" + " tree [B] [N] [C] treestep" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The base-case value `z` is of some type `Z`, the `[N]` function is executed per-node and should accept the node value (whatever it is) and return a value of type `A` (which can be `Z`), and the `[C]` function should expect an `A` and a list of `Z` and return a value of type `Z`:\n", + "If the current tree node is empty then just execute `B`:\n", "\n", - " z :: Z\n", - " N :: node -> A\n", - " C :: A [Z*] -> Z" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If the current tree node is empty then just leave `z` on the stack in lieu:\n", - "\n", - " [] z [N] [C] treestep\n", + " [] [B] [N] [C] treestep\n", " ---------------------------\n", - " z" + " [] B" ] }, { @@ -48,19 +37,26 @@ "source": [ "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`.\n", "\n", - " [node tree*] z [N] [C] treestep\n", - " --------------------------------------- w/ K == z [N] [C] treestep\n", - " node N [tree*] [K] map C" + " [node tree*] [B] [N] [C] treestep\n", + " --------------------------------------- w/ K == [B] [N] [C] treestep\n", + " node N [tree*] [K] map C\n", + "\n", + "(Later on we'll experiment with making `map` part of `C` so you can use other combinators.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Derive the recursive form.\n", - "We can begin to derive it by finding the `ifte` stage that `genrec` will produce. The predicate and base-case functions are trivial, so we just have to derive `J`.\n", + "## Derive the recursive function.\n", + "We can begin to derive it by finding the `ifte` stage that `genrec` will produce.\n", "\n", - " K == [not] [pop z] [J] ifte" + " K == [not] [B] [R0] [R1] genrec\n", + " == [not] [B] [R0 [K] R1] ifte\n", + "\n", + "So we just have to derive `J`:\n", + "\n", + " J == R0 [K] R1" ] }, { @@ -80,7 +76,7 @@ "source": [ "So `J` will have some form like:\n", "\n", - " J == .. [N] .. [K] .. [C] .." + " J == ... [N] ... [K] ... [C] ..." ] }, { @@ -120,9 +116,9 @@ "source": [ "Plug it in and convert to `genrec`:\n", "\n", - " K == [not] [pop z] [J ] ifte\n", - " K == [not] [pop z] [uncons [N] dip [K] map C] ifte\n", - " K == [not] [pop z] [uncons [N] dip] [map C] genrec" + " K == [not] [B] [J ] ifte\n", + " == [not] [B] [uncons [N] dip [K] map C] ifte\n", + " == [not] [B] [uncons [N] dip] [map C] genrec" ] }, { @@ -132,49 +128,49 @@ "## Extract the givens to parameterize the program.\n", "Working backwards:\n", "\n", - " [not] [pop z] [uncons [N] dip] [map C] genrec\n", - " [not] [z] [pop] swoncat [uncons [N] dip] [map C] genrec\n", - " [not] z unit [pop] swoncat [uncons [N] dip] [map C] genrec\n", - " z [not] swap unit [pop] swoncat [uncons [N] dip] [map C] genrec\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" + " [not] [B] [uncons [N] dip] [map C] genrec\n", + " [B] [not] swap [uncons [N] dip] [map C] genrec\n", + " [B] [uncons [N] dip] [[not] swap] dip [map C] genrec\n", + " ^^^^^^^^^^^^^^^^\n", + " [B] [[N] dip] [uncons] swoncat [[not] swap] dip [map C] genrec\n", + " [B] [N] [dip] cons [uncons] swoncat [[not] swap] dip [map C] genrec\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " TS0 == [not] swap unit [pop] swoncat" + "Extract a couple of auxiliary definitions:\n", + "\n", + " TS.0 == [[not] swap] dip\n", + " TS.1 == [dip] cons [uncons] swoncat" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - " z TS0 [uncons [N] dip] [map C] genrec\n", - " z [uncons [N] dip] [TS0] dip [map C] genrec\n", - " z [[N] dip] [uncons] swoncat [TS0] dip [map C] genrec\n", - " z [N] [dip] cons [uncons] swoncat [TS0] dip [map C] genrec\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " TS1 == [dip] cons [uncons] swoncat" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - " z [N] TS1 [TS0] dip [map C] genrec\n", - " z [N] [map C] [TS1 [TS0] dip] dip genrec\n", - " z [N] [C] [map] swoncat [TS1 [TS0] dip] dip genrec\n", + " [B] [N] TS.1 TS.0 [map C] genrec\n", + " [B] [N] [map C] [TS.1 TS.0] dip genrec\n", + " [B] [N] [C] [map] swoncat [TS.1 TS.0] dip genrec\n", "\n", "The givens are all to the left so we have our definition." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### (alternate) Extract the givens to parameterize the program.\n", + "Working backwards:\n", + "\n", + " [not] [B] [uncons [N] dip] [map C] genrec\n", + " [not] [B] [N] [dip] cons [uncons] swoncat [map C] genrec\n", + " [B] [N] [not] roll> [dip] cons [uncons] swoncat [map C] genrec\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -184,7 +180,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -193,15 +189,15 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "DefinitionWrapper.add_definitions('''\n", "\n", - " _treestep_0 == [not] swap unit [pop] swoncat\n", + " _treestep_0 == [[not] swap] dip\n", " _treestep_1 == [dip] cons [uncons] swoncat\n", - " treegrind == [_treestep_1 [_treestep_0] dip] dip genrec\n", + " treegrind == [_treestep_1 _treestep_0] dip genrec\n", " treestep == [map] swoncat treegrind\n", "\n", "''', D)" @@ -214,7 +210,16 @@ "## Examples\n", "Consider trees, the nodes of which are integers. We can find the sum of all nodes in a tree with this function:\n", "\n", - " sumtree == 0 [] [sum +] treestep" + " sumtree == [pop 0] [] [sum +] treestep" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "define('sumtree == [pop 0] [] [sum +] treestep')" ] }, { @@ -223,36 +228,14 @@ "source": [ "Running this function on an empty tree value gives zero:\n", "\n", - " [] 0 [N] [C] treestep\n", - " ---------------------------\n", - " 0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Running it on a non-empty node:\n", - "\n", - " [n tree*] 0 [] [sum +] treestep\n", - " n [tree*] [0 [] [sum +] treestep] map sum +\n", - " n [ ... ] sum +\n", - " n m +\n", - " n+m\n" + " [] [pop 0] [] [sum +] treestep\n", + " ------------------------------------\n", + " 0" ] }, { "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "define('sumtree == 0 [] [sum +] treestep')" - ] - }, - { - "cell_type": "code", - "execution_count": 20, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -267,9 +250,22 @@ "J('[] sumtree') # Empty tree." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Running it on a non-empty node:\n", + "\n", + " [n tree*] [pop 0] [] [sum +] treestep\n", + " n [tree*] [[pop 0] [] [sum +] treestep] map sum +\n", + " n [ ... ] sum +\n", + " n m +\n", + " n+m\n" + ] + }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 5, "metadata": { "scrolled": true }, @@ -288,7 +284,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 6, "metadata": { "scrolled": true }, @@ -307,7 +303,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -324,7 +320,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -341,7 +337,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -353,12 +349,12 @@ } ], "source": [ - "J('[23 [2 [8] [9]] [3] [4 []]] 0 [] [cons sum] treestep') # Alternate \"spelling\"." + "J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [] [cons sum] treestep') # Alternate \"spelling\"." ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 10, "metadata": {}, "outputs": [ { @@ -375,7 +371,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 11, "metadata": {}, "outputs": [ { @@ -392,7 +388,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -409,7 +405,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 13, "metadata": { "scrolled": false }, @@ -423,16 +419,35 @@ } ], "source": [ - "J('[23 [2 [8] [9]] [3] [4 []]] 0 [pop 1] [sum +] treestep') # Combine replace and sum into one function." + "J('[23 [2 [8] [9]] [3] [4 []]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "J('[4 [3 [] [7]]] [pop 0] [pop 1] [sum +] treestep') # Combine replace and sum into one function." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Redefining our BTree in terms of this form.\n", + "## Redefining the Ordered Binary Tree in terms of `treestep`.\n", "\n", - " BTree = [] | [[key value] left right]" + " Tree = [] | [[key value] left right]" ] }, { @@ -455,11 +470,11 @@ "metadata": {}, "source": [ "### Traversal\n", - " [key value] uncons pop [left right] [K] map i\n", - " key [value] pop [left right] [K] map i\n", - " key [left right] [K] map i\n", - " key [lkey rkey ] i\n", - " key lkey rkey" + " [key value] first [left right] [K] map i\n", + " key [value] [left right] [K] map i\n", + " key [left right] [K] map i\n", + " key [lkey rkey ] i\n", + " key lkey rkey" ] }, { @@ -471,19 +486,19 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "3 23 23\n" + "3 'B' 'B'\n" ] } ], "source": [ - "J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] 23 [uncons pop] [i] treestep')" + "J('[[3 0] [[2 0] [][]] [[9 0] [[5 0] [[4 0] [][]] [[8 0] [[6 0] [] [[7 0] [][]]][]]][]]] [\"B\"] [first] [i] treestep')" ] }, { @@ -503,12 +518,12 @@ "\n", "So:\n", "\n", - " [] [flatten cons] [first] treestep" + " [] [first] [flatten cons] treestep" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 16, "metadata": { "scrolled": true }, @@ -536,7 +551,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### In-order traversal with `treestep`.\n", + "### In-order traversal\n", "\n", "From here:\n", "\n", @@ -554,7 +569,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 17, "metadata": {}, "outputs": [ { @@ -573,10 +588,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## with `treegrind`?\n", - "What kind of functions can we write for this with our `treegrind`?\n", - "\n", - "The pattern for processing a non-empty node is:\n", + "## With `treegrind`?\n", + "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:\n", "\n", " node N [tree*] [K] C\n", "\n", @@ -587,77 +600,311 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "23 'N' [[44] [18]] [[not] [pop 'z'] [uncons ['N'] dip] ['C'] genrec] 'C'\n" + "['key' 'value'] 'N' [['left'] ['right']] [[not] ['B'] [uncons ['N'] dip] ['C'] genrec] 'C'\n" ] } ], "source": [ - "J('[23 [44] [18] ] \"z\" [\"N\"] [\"C\"] treegrind')" + "J('[[\"key\" \"value\"] [\"left\"] [\"right\"] ] [\"B\"] [\"N\"] [\"C\"] treegrind')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## `treegrind` with `step`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Iteration through the nodes" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[3 0] 'N' [2 0] 'N' [9 0] 'N' [5 0] 'N' [4 0] 'N' [8 0] 'N' [6 0] 'N' [7 0] 'N'\n" + ] + } + ], + "source": [ + "J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [\"N\"] [step] treegrind')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sum the nodes' keys." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "44\n" + ] + } + ], + "source": [ + "J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [pop] [first +] [step] treegrind')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Rebuild the tree using `map` (imitating `treestep`.)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[103 0] [[102 0] [] []] [[109 0] [[105 0] [[104 0] [] []] [[108 0] [[106 0] [] [[107 0] [] []]] []]] []]]\n" + ] + } + ], + "source": [ + "J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [[100 +] infra] [map cons] treegrind')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Do we have the flexibility to reimplement `Tree-get`?\n", + "I think we do:\n", + "\n", + " [B] [N] [C] treegrind" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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:\n", + "\n", + " [B] [query_key] [C] treegrind" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This means we just have to define `C` from:\n", + "\n", + " [key value] query_key [left right] [K] C\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's try `cmp`:\n", + "\n", + " C == P [T>] [E] [T<] cmp\n", + "\n", + " [key value] query_key [left right] [K] P [T>] [E] [T<] cmp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The predicate `P`\n", + "Seems pretty easy (we must preserve the value in case the keys are equal):\n", + "\n", + " [key value] query_key [left right] [K] P\n", + " [key value] query_key [left right] [K] roll<\n", + " [key value] [left right] [K] query_key [roll< uncons swap] dip\n", + "\n", + " [key value] [left right] [K] roll< uncons swap query_key\n", + " [left right] [K] [key value] uncons swap query_key\n", + " [left right] [K] key [value] swap query_key\n", + " [left right] [K] [value] key query_key\n", + "\n", + " P == roll< [roll< uncons swap] dip\n", + "\n", + "(Possibly with a swap at the end? Or just swap `T<` and `T>`.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So now:\n", + "\n", + " [left right] [K] [value] key query_key [T>] [E] [T<] cmp\n", + "\n", + "Becomes one of these three:\n", + "\n", + " [left right] [K] [value] T>\n", + " [left right] [K] [value] E\n", + " [left right] [K] [value] T<\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `E`\n", + "Easy.\n", + "\n", + " E == roll> popop first" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### `T<` and `T>`\n", + "\n", + " T< == pop [first] dip i\n", + " T> == pop [second] dip i" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Putting it together\n", + "\n", + "\n", + " T> == pop [first] dip i\n", + " T< == pop [second] dip i\n", + " E == roll> popop first\n", + " P == roll< [roll< uncons swap] dip\n", + " \n", + " Tree-get == [P [T>] [E] [T<] cmp] treegrind\n", + "\n", + "To me, that seems simpler than the `genrec` version." + ] + }, + { + "cell_type": "code", + "execution_count": 22, "metadata": {}, "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[3 0] 'N' [2 0] 'N' 23 23 [9 0] 'N' [5 0] 'N' [4 0] 'N' 23 23 [8 0] 'N' [6 0] 'N' 23 [7 0] 'N' 23 23 23 23\n" - ] - } - ], "source": [ - "J('[[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] 23 [\"N\"] [step] treegrind')" + "DefinitionWrapper.add_definitions('''\n", + "\n", + " T> == pop [first] dip i\n", + " T< == pop [second] dip i\n", + " E == roll> popop first\n", + " P == roll< [roll< uncons swap] dip\n", + "\n", + " Tree-get == [P [T>] [E] [T<] cmp] treegrind\n", + "\n", + "''', D)" ] }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 23, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0 3 2 23 23 9 5 4 23 23 8 6 23 7 23 23 23 23\n" - ] - } - ], + "outputs": [], "source": [ - "J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] 23 [first ] [step] treegrind')" + "from joy.library import FunctionWrapper\n", + "from joy.utils.stack import pushback\n", + "\n", + "\n", + "@FunctionWrapper\n", + "def cmp_(stack, expression, dictionary):\n", + " '''\n", + " cmp takes two values and three quoted programs on the stack and runs\n", + " one of the three depending on the results of comparing the two values:\n", + "\n", + " a b [G] [E] [L] cmp\n", + " ------------------------- a > b\n", + " G\n", + "\n", + " a b [G] [E] [L] cmp\n", + " ------------------------- a = b\n", + " E\n", + "\n", + " a b [G] [E] [L] cmp\n", + " ------------------------- a < b\n", + " L\n", + " '''\n", + " L, (E, (G, (b, (a, stack)))) = stack\n", + " expression = pushback(G if a > b else L if a < b else E, expression)\n", + " return stack, expression, dictionary\n", + "\n", + "\n", + "D['cmp'] = cmp_" ] }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "0 [3 [2 [] []] [9 [5 [4 [] []] [8 [6 [] [7 [] []]] []]] []]]\n" + "15\n" ] } ], "source": [ - "J('0 [[3 0] [[2 0] [] []] [[9 0] [[5 0] [[4 0] [] []] [[8 0] [[6 0] [] [[7 0] [] []]] []]] []]] [] [first ] [map cons] treegrind')" + "J('''\\\n", + "\n", + "[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]\n", + "\n", + "[] [5] Tree-get\n", + "\n", + "''')" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'nope'\n" + ] + } + ], + "source": [ + "J('''\\\n", + "\n", + "[[3 13] [[2 12] [] []] [[9 19] [[5 15] [[4 14] [] []] [[8 18] [[6 16] [] [[7 17] [] []]] []]] []]]\n", + "\n", + "[pop \"nope\"] [25] Tree-get\n", + "\n", + "''')" ] }, { diff --git a/docs/Zipper.ipynb b/docs/Zipper.ipynb index 67ca6d0..ceec382 100644 --- a/docs/Zipper.ipynb +++ b/docs/Zipper.ipynb @@ -493,7 +493,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", - "version": "2.7.13" + "version": "2.7.12" } }, "nbformat": 4,