{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Symbolic Evaluation with SymPy" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import sympy\n", "\n", "from joy.joy import run\n", "from joy.library import UnaryBuiltinWrapper\n", "from joy.utils.pretty_print import TracePrinter\n", "from joy.utils.stack import list_to_stack\n", "\n", "from notebook_preamble import D, J, V, define" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "sympy.init_printing()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [SypPy Symbols](http://docs.sympy.org/latest/modules/core.html#module-sympy.core.symbol)\n", "\n", "The SymPy package provides a powerful and elegant [\"thunk\"](https://en.wikipedia.org/wiki/Thunk) object that can take the place of a numeric value in calculations and \"record\" the operations performed on it.\n", "\n", "We can create some of these objects and put them on the Joy stack:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "stack = list_to_stack(sympy.symbols('c a b'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we evaluate the `quadratic` program\n", "\n", " over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2\n", "\n", "The [SypPy Symbols](http://docs.sympy.org/latest/modules/core.html#module-sympy.core.symbol) will become the symbolic expression of the math operations. Unfortunately, the library `sqrt` function doesn't work with the SymPy objects:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "can't convert expression to float\n", " b a c . over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2\n", " b a c a . [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2\n", "b a c a [[[neg] dupdip sqr 4] dipd * * - sqrt pm] . dip 2 * [/] cons app2\n", " b a c . [[neg] dupdip sqr 4] dipd * * - sqrt pm a 2 * [/] cons app2\n", " b a c [[neg] dupdip sqr 4] . dipd * * - sqrt pm a 2 * [/] cons app2\n", " b . [neg] dupdip sqr 4 a c * * - sqrt pm a 2 * [/] cons app2\n", " b [neg] . dupdip sqr 4 a c * * - sqrt pm a 2 * [/] cons app2\n", " b . neg b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2\n", " -b . b sqr 4 a c * * - sqrt pm a 2 * [/] cons app2\n", " -b b . sqr 4 a c * * - sqrt pm a 2 * [/] cons app2\n", " -b b . dup mul 4 a c * * - sqrt pm a 2 * [/] cons app2\n", " -b b b . mul 4 a c * * - sqrt pm a 2 * [/] cons app2\n", " -b b**2 . 4 a c * * - sqrt pm a 2 * [/] cons app2\n", " -b b**2 4 . a c * * - sqrt pm a 2 * [/] cons app2\n", " -b b**2 4 a . c * * - sqrt pm a 2 * [/] cons app2\n", " -b b**2 4 a c . * * - sqrt pm a 2 * [/] cons app2\n", " -b b**2 4 a*c . * - sqrt pm a 2 * [/] cons app2\n", " -b b**2 4*a*c . - sqrt pm a 2 * [/] cons app2\n", " -b -4*a*c + b**2 . sqrt pm a 2 * [/] cons app2\n" ] } ], "source": [ "viewer = TracePrinter()\n", "try:\n", " run('over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2', stack, D, viewer.viewer)\n", "except Exception, e:\n", " print e\n", "viewer.print_()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can pick out that first symbolic expression obect from the Joy stack:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "S, E = viewer.history[-1]" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGUAAAAWCAYAAADZylKgAAAABHNCSVQICAgIfAhkiAAAA3NJREFUaIHt2GuIVVUUB/CfpWU1wlRYTSFDEUHQ5IxCURBMI9EDouhDH3rYNYSgQII+9ADh4oeIpJoi+iAUlUUFlZEETQ0ZvSw1TaJIU5kgMppeGFFWNn1Y+zKn47l35p6544jcP2wOZ+291v6fu/Z67EsbbbQB7sVm7MMo1uO8GWXUhiEsE47owTp8j5NmktSRhtsxhltL6nfgAK6Go1pEqh5uFmTHsHya95pJLErPT0vqzxO++Lk1dOpjAX7Fb458p2zDH5hdUv+lZOPoljEqwCwMYzdWO7ydUhH8+kvqH4u/8ElJ/dXYi7NrgulKXyswIIrZ75NYfwOex04RWb+I7mRZA51+ccK+xX7xYUO4tizpkujBHJG6evEKfhLf/ZbGXdVDWIol2FUTTodTzsUDeBTvTWL9PDyDs/A+HserOBNP4e4CnUFsEI4fxsPpfTEunhr9prE4PbvxoYi6J7EVl+EddBboPYabcCm+nE6Cs7EFO3BcklU1Tl8dOK1A3iWi5quc/P5k72WcUGCru0nOFVNLX2uS/o/oy809m+buy8mfEHeUAfHttdFRkkNDrBKt3UUZWVX5mrIDP2Te+5L9zTimHMWDUDE1p2xRvx2+MM29kJOP1RnVog1GGigUjecyuhfgHzyYs1nV2CknYiU+FrXkQG6PrZm1a5NsSR1bE2GkwbcUjacnsDdH1LMRxZ1Xd7KzrhmSeUO78WcT+t9l7KwVhXplE/rni2J4KjbhRdGr/y1qylJsz6y/XDhuQxN7ZDHo4Pzei2tEXRvJzX02gb0eEbHrxYHMo5ZKv2mKZYvQafKnbzCjt10cgv4Cm6vS+jvS+9z0vq3F3CvKp6/lSfeuOvOPpPmrmjFa9rKTx37RcRRhkagFH4gasTHJF4hIGcK7OZ1O4+1w7ZY8Kz1PmTrdlqHWeRX9Z9WF2/C1yAaHFaqKa8r8JN8pcnMNJwtHjYk0Njcz93mSX1+wzznK3YgrykfKpqS7x/87wQ68LerjFc0abVWklMGo6OEHxG14WJyuK0XN+Ff079kadw9eF7XnFnwhoqpXRF7XIeJO/HY9Ip0eL+rPa+KGfx1Ox5148xBymjSq6ndf80UvPyruJB+J4t5n/BKWxyV4w3hDsFekhxtL8qsoFykLk94anCEuvPvSGCphr4022mijjTZajv8AHtTyPwIcKPQAAAAASUVORK5CYII=\n", "text/latex": [ "$$- 4 a c + b^{2}$$" ], "text/plain": [ " 2\n", "-4⋅a⋅c + b " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "q = S[0]\n", "q" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Python `math.sqrt()` function causes the \"can't convert expression to float\" exception but `sympy.sqrt()` does not:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAHoAAAAdCAYAAABlqHgGAAAABHNCSVQICAgIfAhkiAAABGhJREFUaIHt2muIVVUUwPGfpqU1ghVWFpMUJJVZPnpgUExK9AAthPrQQ8cQgoIIMnqANPghelBalIRgL3tCmSVBlmVU9lDTLHpoD6aIpKwMQ0pKpw/rDF6v597uOffMVeT84XDn7L3X2uucvfdaa+8zlJSU7D/0yyk3FFuKNKRk32Q6LtvbRpT0Pc9gyN42oqRx+ueQOTC5/izYlpI+JM9AT8TbBdtRsg/yMI7d20aUZCPPim7HD0UbUpKJ27AaW7EZS3FKPYGsAz0Wn+QyraRIOjAfZ4tQ+i+W47CiOrgDZxSlrARchx5c04SONuzA5FoNsq7o8VjThEFZuVq8hB7MbGG/rWRc8vtxEzqGiLH8vXlzOAaPFKGoQdrxh9jG7c8DvQ5/YUATOp5P9BxQq0Haiq61yieLoN8K+uEx/Ka1kysPnWIiduSQPQij8KmIs3m4F+eKk8odtRpVD+pkfJlSDpPwZk5jsnKDSDJmYFsD7a/A09goPMAWkZXOqCPTIVbCj9iOTViGS/ManYPRGCjc9hi8KCb3NrzufzJp3IdpYmy+qdewckBPFw9/gsjmKjlEzJa/G7G+SU7CXXgA7zTQfgiewPF4Fw9hMY7Do7glRWYeVojJtBz3J/fj7fnsfcn45HcEVgrPsBBrcT7eEh+Q0ngQV+E8fJGn85W4p6psquaywkYZIJK9DRiclHWpH6PbcFRK+XCxur+qKr8z0feCmMDVukZktLlTfte9IJH9VWxdK3kyqbs9RW6+2ENPFM/ee7Vl6fxm8aIrWYgjsijJyRzhOSZUlHXJn4xtwC8V92MT/avFeX0RdMo/0GvU3lqdldQ9m1LXU+PqytL5yEToxOS+P5Y0INddx4C066kq+TNFQlLtTbrUH+hDMRsfiti8o6qftRVtFyVlkxp4njS6ZXvGx+voGihyg27pGfeIRMdLOW3djbQONoqVMEW4vQn4qAFd38oWw3+qsmNR0vfsDDpOFUnLkViF58Re8h8Ro6dhfUX7C8RkWJGhj0rm2TNmjsElIk/orqqrd4o4WniVpdIz7t4Q8n1mKzNwt4jVvX+P6svOxMtrdJXMq5BbLyZXR4rOOUn765P7Qcn9uoJt75TPdc9M5G6qUT83qb84r2GV1Nqkv4xZIi6fjM+L6KwO20UekMY4EVvfE57mg6S8XazoZfb8bDrUrq1V74lT779NtSLXaITejDvtfHo4rsXXwmP1Gf3xs8hQ5/ZlRw3QJT1GD0vKN4p418vhYvB7hAsfVFH3WVJ+eUo/I9U5WapDp3wrelUi953ds/82vCFyjQtz2JNKrRW9U8SOWUV2VjCbxT5zosghlouVcJGIwTvF/rIyb7gVr4hYPl14qqEizrYn8q1ggIjR63CwiOVLxEnZVByNG/FaK4yZIhKXZs5gi6BL7ax7mNhvbhZ75vdFAjbWrsOHas7Bq3YlbZuEe7wyp32dsq/o0xKZBeIbwmKxL94qvFEWXU0zWHzgLikpKSkpKWk9/wEOzhV2ng+cdgAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\sqrt{- 4 a c + b^{2}}$$" ], "text/plain": [ " _____________\n", " ╱ 2 \n", "╲╱ -4⋅a⋅c + b " ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "sympy.sqrt(q)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Use `sympy.sqrt`\n", "This is easy to fix." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "D['sqrt'] = UnaryBuiltinWrapper(sympy.sqrt)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now it works just fine." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "(root1, (root2, _)) = run('over [[[neg] dupdip sqr 4] dipd * * - sqrt pm] dip 2 * [/] cons app2', stack, D)[0]" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/latex": [ "$$\\frac{1}{2 a} \\left(- b - \\sqrt{- 4 a c + b^{2}}\\right)$$" ], "text/plain": [ " _____________\n", " ╱ 2 \n", "-b - ╲╱ -4⋅a⋅c + b \n", "─────────────────────\n", " 2⋅a " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "root1" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/latex": [ "$$\\frac{1}{2 a} \\left(- b + \\sqrt{- 4 a c + b^{2}}\\right)$$" ], "text/plain": [ " _____________\n", " ╱ 2 \n", "-b + ╲╱ -4⋅a⋅c + b \n", "─────────────────────\n", " 2⋅a " ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "root2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "At some point I will probably make an optional library of Joy wrappers for SymPy functions, and either load it automatically if SymPy installation is available or have a CLI switch or something. There's a huge amount of incredibly useful stuff and I don't see why Joy shouldn't expose another interface for using it. (As an example, the symbolic expressions can be \"lambdafied\" into very fast versions, i.e. a function that takes `a`, `b`, and `c` and computes the value of the root using just low-level fast code, bypassing Joy and Python. Also, Numpy, &c.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Partial Evaluation\n", "\n", "[Futamura projections](https://en.wikipedia.org/wiki/Futamura_projection)\n", "\n", "Starting with the example from [Partial Computation of Programs](http://hdl.handle.net/2433/103401)\n", "by [Yoshihiko Futamura](http://fi.ftmr.info/) of a function to compute `u` to the `k`th power:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "def F(u, k):\n", " z = 1\n", " while k != 0:\n", " if odd(k):\n", " z = z * u\n", " k = k / 2\n", " u = u * u\n", " return z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Partial evaluation with `k = 5`:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "def F5(u):\n", " z = 1 * u\n", " u = u * u\n", " u = u * u\n", " z = z * u\n", " return z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Translate `F(u, k)` to Joy\n", "\n", " u k 1 # z = 1\n", " [pop] [Fw] while # the while statement\n", " popopd # discard u k, \"return\" z" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What's Fw?\n", "\n", "\n", " u k z [pop odd] [Ft] [] ifte # the if statement\n", " [2 //] dip # k = k / 2 floordiv\n", " [sqr] dipd # u = u * u\n", "\n", " [[sqr] dip 2 //] dip # We can merge last two lines." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Helper function Ft (to compute z = z * u).\n", "\n", "\n", " u k z Ft\n", " ---------------\n", " u k u*z\n", "\n", "\n", " Ft == [over] dip *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Putting it together:\n", "\n", " Ft == [over] dip *\n", " Fb == [[sqr] dip 2 //] dip\n", " Fw == [pop odd] [Ft] [] ifte Fb\n", " F == 1 [pop] [Fw] while popopd" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "define('odd == 2 %')" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "define('Ft == [over] dip *')" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "define('Fb == [[sqr] dip 2 //] dip')" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "define('Fw == [pop odd] [Ft] [] ifte Fb')" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "define('F == 1 [pop] [Fw] while popopd')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Try it out:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "32\n" ] } ], "source": [ "J('2 5 F')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In order to elide the tests let's define special versions of `while` and `ifte`:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "from joy.joy import joy\n", "from joy.library import FunctionWrapper\n", "from joy.parser import Symbol\n", "from joy.utils.stack import concat\n", "\n", "\n", "S_while = Symbol('while')\n", "\n", "\n", "@FunctionWrapper\n", "def while_(S, expression, dictionary):\n", " '''[if] [body] while'''\n", " (body, (if_, stack)) = S\n", " if joy(stack, if_, dictionary)[0][0]:\n", " expression = concat(body, (if_, (body, (S_while, expression))))\n", " return stack, expression, dictionary\n", "\n", "\n", "@FunctionWrapper\n", "def ifte(stack, expression, dictionary):\n", " '''[if] [then] [else] ifte'''\n", " (else_, (then, (if_, stack))) = stack\n", " if_res = joy(stack, if_, dictionary)[0][0]\n", " quote = then if if_res else else_\n", " expression = concat(quote, expression)\n", " return (stack, expression, dictionary)\n", "\n", "\n", "D['ifte'] = ifte\n", "D['while'] = while_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And with a SymPy symbol for the `u` argument:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " u 5 . F\n", " u 5 . 1 [pop] [Fw] while popopd\n", " u 5 1 . [pop] [Fw] while popopd\n", " u 5 1 [pop] . [Fw] while popopd\n", " u 5 1 [pop] [Fw] . while popopd\n", " u 5 1 . Fw [pop] [Fw] while popopd\n", " u 5 1 . [pop odd] [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u 5 1 [pop odd] . [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u 5 1 [pop odd] [Ft] . [] ifte Fb [pop] [Fw] while popopd\n", " u 5 1 [pop odd] [Ft] [] . ifte Fb [pop] [Fw] while popopd\n", " u 5 1 . Ft Fb [pop] [Fw] while popopd\n", " u 5 1 . [over] dip * Fb [pop] [Fw] while popopd\n", " u 5 1 [over] . dip * Fb [pop] [Fw] while popopd\n", " u 5 . over 1 * Fb [pop] [Fw] while popopd\n", " u 5 u . 1 * Fb [pop] [Fw] while popopd\n", " u 5 u 1 . * Fb [pop] [Fw] while popopd\n", " u 5 u . Fb [pop] [Fw] while popopd\n", " u 5 u . [[sqr] dip 2 //] dip [pop] [Fw] while popopd\n", " u 5 u [[sqr] dip 2 //] . dip [pop] [Fw] while popopd\n", " u 5 . [sqr] dip 2 // u [pop] [Fw] while popopd\n", " u 5 [sqr] . dip 2 // u [pop] [Fw] while popopd\n", " u . sqr 5 2 // u [pop] [Fw] while popopd\n", " u . dup mul 5 2 // u [pop] [Fw] while popopd\n", " u u . mul 5 2 // u [pop] [Fw] while popopd\n", " u**2 . 5 2 // u [pop] [Fw] while popopd\n", " u**2 5 . 2 // u [pop] [Fw] while popopd\n", " u**2 5 2 . // u [pop] [Fw] while popopd\n", " u**2 2 . u [pop] [Fw] while popopd\n", " u**2 2 u . [pop] [Fw] while popopd\n", " u**2 2 u [pop] . [Fw] while popopd\n", " u**2 2 u [pop] [Fw] . while popopd\n", " u**2 2 u . Fw [pop] [Fw] while popopd\n", " u**2 2 u . [pop odd] [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u**2 2 u [pop odd] . [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u**2 2 u [pop odd] [Ft] . [] ifte Fb [pop] [Fw] while popopd\n", " u**2 2 u [pop odd] [Ft] [] . ifte Fb [pop] [Fw] while popopd\n", " u**2 2 u . Fb [pop] [Fw] while popopd\n", " u**2 2 u . [[sqr] dip 2 //] dip [pop] [Fw] while popopd\n", " u**2 2 u [[sqr] dip 2 //] . dip [pop] [Fw] while popopd\n", " u**2 2 . [sqr] dip 2 // u [pop] [Fw] while popopd\n", " u**2 2 [sqr] . dip 2 // u [pop] [Fw] while popopd\n", " u**2 . sqr 2 2 // u [pop] [Fw] while popopd\n", " u**2 . dup mul 2 2 // u [pop] [Fw] while popopd\n", " u**2 u**2 . mul 2 2 // u [pop] [Fw] while popopd\n", " u**4 . 2 2 // u [pop] [Fw] while popopd\n", " u**4 2 . 2 // u [pop] [Fw] while popopd\n", " u**4 2 2 . // u [pop] [Fw] while popopd\n", " u**4 1 . u [pop] [Fw] while popopd\n", " u**4 1 u . [pop] [Fw] while popopd\n", " u**4 1 u [pop] . [Fw] while popopd\n", " u**4 1 u [pop] [Fw] . while popopd\n", " u**4 1 u . Fw [pop] [Fw] while popopd\n", " u**4 1 u . [pop odd] [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u**4 1 u [pop odd] . [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u**4 1 u [pop odd] [Ft] . [] ifte Fb [pop] [Fw] while popopd\n", " u**4 1 u [pop odd] [Ft] [] . ifte Fb [pop] [Fw] while popopd\n", " u**4 1 u . Ft Fb [pop] [Fw] while popopd\n", " u**4 1 u . [over] dip * Fb [pop] [Fw] while popopd\n", " u**4 1 u [over] . dip * Fb [pop] [Fw] while popopd\n", " u**4 1 . over u * Fb [pop] [Fw] while popopd\n", " u**4 1 u**4 . u * Fb [pop] [Fw] while popopd\n", " u**4 1 u**4 u . * Fb [pop] [Fw] while popopd\n", " u**4 1 u**5 . Fb [pop] [Fw] while popopd\n", " u**4 1 u**5 . [[sqr] dip 2 //] dip [pop] [Fw] while popopd\n", "u**4 1 u**5 [[sqr] dip 2 //] . dip [pop] [Fw] while popopd\n", " u**4 1 . [sqr] dip 2 // u**5 [pop] [Fw] while popopd\n", " u**4 1 [sqr] . dip 2 // u**5 [pop] [Fw] while popopd\n", " u**4 . sqr 1 2 // u**5 [pop] [Fw] while popopd\n", " u**4 . dup mul 1 2 // u**5 [pop] [Fw] while popopd\n", " u**4 u**4 . mul 1 2 // u**5 [pop] [Fw] while popopd\n", " u**8 . 1 2 // u**5 [pop] [Fw] while popopd\n", " u**8 1 . 2 // u**5 [pop] [Fw] while popopd\n", " u**8 1 2 . // u**5 [pop] [Fw] while popopd\n", " u**8 0 . u**5 [pop] [Fw] while popopd\n", " u**8 0 u**5 . [pop] [Fw] while popopd\n", " u**8 0 u**5 [pop] . [Fw] while popopd\n", " u**8 0 u**5 [pop] [Fw] . while popopd\n", " u**8 0 u**5 . popopd\n", " u**5 . \n" ] } ], "source": [ "stack = list_to_stack([5, sympy.symbols('u')])\n", "viewer = TracePrinter()\n", "try:\n", " (result, _) = run('F', stack, D, viewer.viewer)[0]\n", "except Exception, e:\n", " print e\n", "viewer.print_()" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAWCAYAAADafVyIAAAABHNCSVQICAgIfAhkiAAAAUpJREFUSInt1DtLXUEUBeBPESLXFGITsDEqEdHKaLBMQBvFRsh/SG9nKouAjY0/IsQm2lgoNrENeaEgaKGVjyBaBLQQNRYzSYbjOVduzoWkcMGwmb1n1pr9YPjPMYOfmXWUHmiqg8g2XiT7q3oLXMq8OkVjHQS6sI89vMPjNNhQknwMFezgEabRh36cluTORQu+Y+qXI1ui18IkTOZc7oixxSoCZ9jCkyKBp9F+zrk8FO3XKgLN6MVh0YE9HBfEZoUMJhLfHJ6jE8NYxg8h21toiwQrBQJrMd6e+BZwgAthkt4LTc7FaCR4UxA/ERpYE9IeDEabV/8uIcMvZQQGos0jGY+2WoPvxDehllk8wKZQvpdlBD5Gkp7E14K3/vyU3bWSpp/dKp5hHUt4iBFsCHNdwe5fPPw3mjEvjN05PuEVWnGND2XI7/HvcAOaJEK/e6V+UwAAAABJRU5ErkJggg==\n", "text/latex": [ "$$u^{5}$$" ], "text/plain": [ " 5\n", "u " ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's try partial evaluation by hand and use a \"stronger\" thunk.\n", "\n", "Caret underscoring indicates terms that form thunks. When an arg is unavailable for a computation we just postpone it until the arg becomes available and in the meantime treat the pending computation as one unit.\n", "\n", " u 5 . F\n", " u 5 . 1 [pop] [Fw] while popopd\n", " u 5 1 . [pop] [Fw] while popopd\n", " u 5 1 [pop] . [Fw] while popopd\n", " u 5 1 [pop] [Fw] . while popopd\n", " u 5 1 . Fw [pop] [Fw] while popopd\n", " u 5 1 . [pop odd] [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u 5 1 [pop odd] . [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u 5 1 [pop odd] [Ft] . [] ifte Fb [pop] [Fw] while popopd\n", " u 5 1 [pop odd] [Ft] [] . ifte Fb [pop] [Fw] while popopd\n", " u 5 1 . Ft Fb [pop] [Fw] while popopd\n", " u 5 1 . [over] dip * Fb [pop] [Fw] while popopd\n", " u 5 1 [over] . dip * Fb [pop] [Fw] while popopd\n", " u 5 . over 1 * Fb [pop] [Fw] while popopd\n", " u 5 u . 1 * Fb [pop] [Fw] while popopd\n", " u 5 u 1 . * Fb [pop] [Fw] while popopd\n", " u 5 u . Fb [pop] [Fw] while popopd\n", " u 5 u . [[sqr] dip 2 //] dip [pop] [Fw] while popopd\n", " u 5 u [[sqr] dip 2 //] . dip [pop] [Fw] while popopd\n", " u 5 . [sqr] dip 2 // u [pop] [Fw] while popopd\n", " u 5 [sqr] . dip 2 // u [pop] [Fw] while popopd\n", " u . sqr 5 2 // u [pop] [Fw] while popopd\n", " u . dup mul 5 2 // u [pop] [Fw] while popopd\n", " u dup * . 5 2 // u [pop] [Fw] while popopd\n", " ^^^^^^^" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " u dup * 2 u [pop] [Fw] . while popopd\n", " u dup * 2 u . Fw [pop] [Fw] while popopd\n", " u dup * 2 u . [pop odd] [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u dup * 2 u [pop odd] . [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " u dup * 2 u [pop odd] [Ft] . [] ifte Fb [pop] [Fw] while popopd\n", " u dup * 2 u [pop odd] [Ft] [] . ifte Fb [pop] [Fw] while popopd\n", " u dup * 2 u . Fb [pop] [Fw] while popopd\n", " u dup * 2 u . [[sqr] dip 2 //] dip [pop] [Fw] while popopd\n", " u dup * 2 u [[sqr] dip 2 //] . dip [pop] [Fw] while popopd\n", " u dup * 2 . [sqr] dip 2 // u [pop] [Fw] while popopd\n", " u dup * 2 [sqr] . dip 2 // u [pop] [Fw] while popopd\n", " u dup * . sqr 2 2 // u [pop] [Fw] while popopd\n", " u dup * . dup mul 2 2 // u [pop] [Fw] while popopd\n", " u dup * dup * . 2 2 // u [pop] [Fw] while popopd\n", " ^^^^^^^^^^^^^\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "w/ `K == u dup * dup *`\n", "\n", " K 1 u [pop] [Fw] . while popopd\n", " K 1 u . Fw [pop] [Fw] while popopd\n", " K 1 u . [pop odd] [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " K 1 u [pop odd] . [Ft] [] ifte Fb [pop] [Fw] while popopd\n", " K 1 u [pop odd] [Ft] . [] ifte Fb [pop] [Fw] while popopd\n", " K 1 u [pop odd] [Ft] [] . ifte Fb [pop] [Fw] while popopd\n", " K 1 u . Ft Fb [pop] [Fw] while popopd\n", " K 1 u . [over] dip * Fb [pop] [Fw] while popopd\n", " K 1 u [over] . dip * Fb [pop] [Fw] while popopd\n", " K 1 . over u * Fb [pop] [Fw] while popopd\n", " K 1 K . u * Fb [pop] [Fw] while popopd\n", " K 1 K u . * Fb [pop] [Fw] while popopd\n", " K 1 K u * . Fb [pop] [Fw] while popopd\n", " ^^^^^" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "w/ `L == K u *`\n", "\n", " K 1 L . Fb [pop] [Fw] while popopd\n", " K 1 L . [[sqr] dip 2 //] dip [pop] [Fw] while popopd\n", " K 1 L [[sqr] dip 2 //] . dip [pop] [Fw] while popopd\n", " K 1 . [sqr] dip 2 // L [pop] [Fw] while popopd\n", " K 1 [sqr] . dip 2 // L [pop] [Fw] while popopd\n", " K . sqr 1 2 // L [pop] [Fw] while popopd\n", " K . dup mul 1 2 // L [pop] [Fw] while popopd\n", " K K . mul 1 2 // L [pop] [Fw] while popopd\n", " K K * . 1 2 // L [pop] [Fw] while popopd\n", " ^^^^^\n", " K K * . 1 2 // L [pop] [Fw] while popopd\n", " K K * 1 . 2 // L [pop] [Fw] while popopd\n", " K K * 1 2 . // L [pop] [Fw] while popopd\n", " K K * 0 . L [pop] [Fw] while popopd\n", " K K * 0 L . [pop] [Fw] while popopd\n", " K K * 0 L [pop] . [Fw] while popopd\n", " K K * 0 L [pop] [Fw] . while popopd\n", " ^^^^^\n", " K K * 0 L . popopd\n", " L . " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So:\n", "\n", " K == u dup * dup *\n", " L == K u *\n", "\n", "Our result \"thunk\" would be:\n", " \n", " u dup * dup * u *\n", "\n", "Mechanically, you could do:\n", "\n", " u dup * dup * u *\n", " u u [dup * dup *] dip *\n", " u dup [dup * dup *] dip *\n", "\n", "\n", " F5 == dup [dup * dup *] dip *\n", "\n", "But we can swap the two arguments to the final `*` to get all mentions of `u` to the left:\n", "\n", "\n", " u u dup * dup * *\n", "\n", "\n", "Then de-duplicate \"u\":\n", "\n", "\n", " u dup dup * dup * *\n", "\n", "\n", "To arrive at a startlingly elegant form for F5:\n", "\n", "\n", " F5 == dup dup * dup * *" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " u . dup dup * dup * *\n", " u u . dup * dup * *\n", " u u u . * dup * *\n", " u u**2 . dup * *\n", "u u**2 u**2 . * *\n", " u u**4 . *\n", " u**5 . \n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAABgAAAAWCAYAAADafVyIAAAABHNCSVQICAgIfAhkiAAAAUpJREFUSInt1DtLXUEUBeBPESLXFGITsDEqEdHKaLBMQBvFRsh/SG9nKouAjY0/IsQm2lgoNrENeaEgaKGVjyBaBLQQNRYzSYbjOVduzoWkcMGwmb1n1pr9YPjPMYOfmXWUHmiqg8g2XiT7q3oLXMq8OkVjHQS6sI89vMPjNNhQknwMFezgEabRh36cluTORQu+Y+qXI1ui18IkTOZc7oixxSoCZ9jCkyKBp9F+zrk8FO3XKgLN6MVh0YE9HBfEZoUMJhLfHJ6jE8NYxg8h21toiwQrBQJrMd6e+BZwgAthkt4LTc7FaCR4UxA/ERpYE9IeDEabV/8uIcMvZQQGos0jGY+2WoPvxDehllk8wKZQvpdlBD5Gkp7E14K3/vyU3bWSpp/dKp5hHUt4iBFsCHNdwe5fPPw3mjEvjN05PuEVWnGND2XI7/HvcAOaJEK/e6V+UwAAAABJRU5ErkJggg==\n", "text/latex": [ "$$u^{5}$$" ], "text/plain": [ " 5\n", "u " ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stack = list_to_stack([sympy.symbols('u')])\n", "viewer = TracePrinter()\n", "try:\n", " (result, _) = run('dup dup * dup * *', stack, D, viewer.viewer)[0]\n", "except Exception, e:\n", " print e\n", "viewer.print_()\n", "result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I'm not sure how to implement these kinds of thunks. I think you have to have support in the interpreter, or you have to modify all of the functions like `dup` to check for thunks in their inputs." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Working on the compiler, from this:\n", "\n", " dup dup * dup * *\n", "\n", "We can already generate:\n", "\n", " ---------------------------------\n", " (a0, stack) = stack\n", " a1 = mul(a0, a0)\n", " a2 = mul(a1, a1)\n", " a3 = mul(a2, a0)\n", " stack = (a3, stack)\n", " ---------------------------------\n", "\n", "This is pretty old stuff... (E.g. from 1999, M. Anton Ertl [Compilation of Stack-Based Languages](http://www.complang.tuwien.ac.at/projects/rafts.html) he goes a lot further for Forth.)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## \"A Transformation Based Approach to Semantics-Directed Code Generation\"\n", "\n", "by Arthur Nunes-Harwitt\n", "\n", "https://dl.acm.org/citation.cfm?doid=2635648.2635652\n", "\n" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "6\n" ] } ], "source": [ "def m(x, y): return x * y\n", "\n", "print m(2, 3)" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "6\n" ] } ], "source": [ "def m(x): return lambda y: x * y\n", "\n", "print m(2)(3)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "lambda y: 2 * y\n", "6\n" ] } ], "source": [ "def m(x): return \"lambda y: %(x)s * y\" % locals()\n", "\n", "print m(2)\n", "print eval(m(2))(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Joy:\n", "\n", " m == [*] cons\n", "\n", " 3 2 m i\n", " 3 2 [*] cons i\n", " 3 [2 *] i\n", " 3 2 *\n", " 6\n" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "lambda b: 1 if 3 == 0 else b * p(3 - 1, b)\n" ] } ], "source": [ "def p(n, b): # original\n", " return 1 if n == 0 else b * p(n - 1, b)\n", "\n", "\n", "def p(n): # curried\n", " return lambda b: 1 if n == 0 else b * p(n - 1, b)\n", "\n", "\n", "def p(n): # quoted\n", " return \"lambda b: 1 if %(n)s == 0 else b * p(%(n)s - 1, b)\" % locals()\n", "\n", "\n", "print p(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Original\n", "\n", " p == [0 =] [popop 1] [-- over] [dip *] genrec\n", "\n", " b n p\n", " b n [0 =] [popop 1] [-- over [p] dip *]\n", "\n", " b n -- over [p] dip *\n", " b n-1 over [p] dip *\n", " b n-1 b [p] dip *\n", " b n-1 p b *\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "curried, quoted\n", "\n", " n p\n", " ---------------------------------------------\n", " [[n 0 =] [pop 1] [dup n --] [*] genrec]" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "lambda b: b * p(3 - 1, b)\n" ] } ], "source": [ "def p(n): # lambda lowered\n", " return (\n", " lambda b: 1\n", " if n == 0 else\n", " lambda b: b * p(n - 1, b)\n", " )\n", "\n", "\n", "def p(n): # lambda lowered quoted\n", " return (\n", " \"lambda b: 1\"\n", " if n == 0 else\n", " \"lambda b: b * p(%(n)s - 1, b)\" % locals()\n", " )\n", "\n", "print p(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " p == [0 =] [[pop 1]] [ [-- [dup] dip p *] cons ]ifte\n", "\n", "\n", " 3 p\n", " 3 [-- [dup] dip p *] cons\n", " [3 -- [dup] dip p *]\n" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8\n" ] } ], "source": [ "def p(n): # expression lifted\n", " if n == 0:\n", " return lambda b: 1\n", " f = p(n - 1)\n", " return lambda b: b * f(b)\n", "\n", "\n", "print p(3)(2)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "lambda b: b * (lambda b: b * (lambda b: b * (lambda b: 1)(b))(b))(b)\n", "8\n" ] } ], "source": [ "def p(n): # quoted\n", " if n == 0:\n", " return \"lambda b: 1\"\n", " f = p(n - 1)\n", " return \"lambda b: b * (%(f)s)(b)\" % locals()\n", "\n", "print p(3)\n", "print eval(p(3))(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " p == [0 =] [pop [pop 1]] [-- p [dupdip *] cons] ifte\n", "\n", "\n", " 3 p\n", " 3 -- p [dupdip *] cons\n", " 2 p [dupdip *] cons\n", " 2 -- p [dupdip *] cons [dupdip *] cons\n", " 1 p [dupdip *] cons [dupdip *] cons\n", " 1 -- p [dupdip *] cons [dupdip *] cons [dupdip *] cons\n", " 0 p [dupdip *] cons [dupdip *] cons [dupdip *] cons\n", " 0 pop [pop 1] [dupdip *] cons [dupdip *] cons [dupdip *] cons\n", " [pop 1] [dupdip *] cons [dupdip *] cons [dupdip *] cons\n", " ...\n", " [[[[pop 1] dupdip *] dupdip *] dupdip *]\n", "\n", "\n", " 2 [[[[pop 1] dupdip *] dupdip *] dupdip *] i\n", " 2 [[[pop 1] dupdip *] dupdip *] dupdip *\n", " 2 [[pop 1] dupdip *] dupdip * 2 *\n", " 2 [pop 1] dupdip * 2 * 2 *\n", " 2 pop 1 2 * 2 * 2 *\n", " 1 2 * 2 * 2 *\n", "\n", "\n", "\n", " p == [0 =] [pop [pop 1]] [-- p [dupdip *] cons] ifte\n", " p == [0 =] [pop [pop 1]] [-- [p] i [dupdip *] cons] ifte\n", " p == [0 =] [pop [pop 1]] [--] [i [dupdip *] cons] genrec" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [], "source": [ "define('p == [0 =] [pop [pop 1]] [--] [i [dupdip *] cons] genrec')" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[[[pop 1] dupdip *] dupdip *] dupdip *]\n" ] } ], "source": [ "J('3 p')" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " . 2 [[[[pop 1] dupdip *] dupdip *] dupdip *] i\n", " 2 . [[[[pop 1] dupdip *] dupdip *] dupdip *] i\n", "2 [[[[pop 1] dupdip *] dupdip *] dupdip *] . i\n", " 2 . [[[pop 1] dupdip *] dupdip *] dupdip *\n", " 2 [[[pop 1] dupdip *] dupdip *] . dupdip *\n", " 2 . [[pop 1] dupdip *] dupdip * 2 *\n", " 2 [[pop 1] dupdip *] . dupdip * 2 *\n", " 2 . [pop 1] dupdip * 2 * 2 *\n", " 2 [pop 1] . dupdip * 2 * 2 *\n", " 2 . pop 1 2 * 2 * 2 *\n", " . 1 2 * 2 * 2 *\n", " 1 . 2 * 2 * 2 *\n", " 1 2 . * 2 * 2 *\n", " 2 . 2 * 2 *\n", " 2 2 . * 2 *\n", " 4 . 2 *\n", " 4 2 . *\n", " 8 . \n" ] } ], "source": [ "V('2 [[[[pop 1] dupdip *] dupdip *] dupdip *] i')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "stack = list_to_stack([sympy.symbols('u')])\n", "(result, s) = run('p i', stack, D)[0]\n", "result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "From this:\n", "\n", " p == [0 =] [pop pop 1] [-- over] [dip *] genrec\n", "\n", "To this:\n", "\n", " p == [0 =] [pop [pop 1]] [--] [i [dupdip *] cons] genrec\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Try it with `F()`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def odd(n): return n % 2\n", "\n", "\n", "def F(u, k):\n", " z = 1\n", " while k != 0:\n", " if odd(k):\n", " z = z * u\n", " k = k / 2\n", " u = u * u\n", " return z\n", "\n", "F(2, 5)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(k):\n", " def _F(u, k=k):\n", " z = 1\n", " while k != 0:\n", " if odd(k):\n", " z = z * u\n", " k = k / 2\n", " u = u * u\n", " return z\n", " return _F\n", " \n", "F(5)(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(k):\n", " def _F(u, k=k):\n", " if k == 0:\n", " z = 1\n", " else:\n", " z = F(k / 2)(u)\n", " z *= z\n", " if odd(k):\n", " z = z * u\n", " return z\n", " return _F\n", " \n", "F(5)(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(k):\n", " if k == 0:\n", " z = lambda u: 1\n", " else:\n", " f = F(k / 2)\n", " def z(u):\n", " uu = f(u)\n", " uu *= uu\n", " return uu * u if odd(k) else uu\n", " return z\n", " \n", "F(5)(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(k):\n", " if k == 0:\n", " z = lambda u: 1\n", " else:\n", " f = F(k / 2)\n", " if odd(k):\n", " z = lambda u: (lambda fu, u: fu * fu * u)(f(u), u)\n", " else:\n", " z = lambda u: (lambda fu, u: fu * fu)(f(u), u)\n", " return z\n", " \n", "F(5)(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(k):\n", " if k == 0:\n", " z = \"lambda u: 1\"\n", " else:\n", " f = F(k / 2)\n", " if odd(k):\n", " z = \"lambda u: (lambda fu, u: fu * fu * u)((%(f)s)(u), u)\" % locals()\n", " else:\n", " z = \"lambda u: (lambda fu, u: fu * fu)((%(f)s)(u), u)\" % locals()\n", " return z\n", " \n", "source = F(5)\n", "print source\n", "eval(source)(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hmm..." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for n in range(4):\n", " print F(n)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(k):\n", " if k == 0:\n", " z = \"lambda u: 1\"\n", " elif k == 1:\n", " z = \"lambda u: u\"\n", " else:\n", " f = F(k / 2)\n", " if odd(k):\n", " z = \"lambda u: (lambda fu, u: fu * fu * u)((%(f)s)(u), u)\" % locals()\n", " else:\n", " z = \"lambda u: (lambda fu, u: fu * fu)((%(f)s)(u), u)\" % locals()\n", " return z\n", " \n", "source = F(5)\n", "print source\n", "eval(source)(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for n in range(4):\n", " print F(n)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(k):\n", " if k == 0:\n", " z = \"lambda u: 1\"\n", " elif k == 1:\n", " z = \"lambda u: u\"\n", " else:\n", " m = k / 2\n", " if odd(k):\n", " if m == 0:\n", " z = \"lambda u: 1\"\n", " elif m == 1:\n", " z = \"lambda u: u * u * u\"\n", " else:\n", " z = \"lambda u: (lambda fu, u: fu * fu * u)((%s)(u), u)\" % F(m)\n", " else:\n", " if m == 0:\n", " z = \"lambda u: 1\"\n", " elif m == 1:\n", " z = \"lambda u: u * u\"\n", " else:\n", " z = \"lambda u: (lambda u: u * u)((%s)(u))\" % F(m)\n", " return z\n", " \n", "source = F(5)\n", "print source\n", "eval(source)(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(k):\n", " if k == 0:\n", " z = \"lambda u: 1\"\n", " elif k == 1:\n", " z = \"lambda u: u\"\n", " else:\n", " m = k / 2\n", " if m == 0:\n", " z = \"lambda u: 1\"\n", " \n", " elif odd(k):\n", " if m == 1:\n", " z = \"lambda u: u * u * u\"\n", " else:\n", " z = \"lambda u: (lambda fu, u: fu * fu * u)((%s)(u), u)\" % F(m)\n", " else:\n", " if m == 1:\n", " z = \"lambda u: u * u\"\n", " else:\n", " z = \"lambda u: (lambda u: u * u)((%s)(u))\" % F(m)\n", " return z\n", " \n", "source = F(5)\n", "print source\n", "eval(source)(2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "for n in range(7):\n", " source = F(n)\n", " print n, '%2i' % eval(source)(2), source" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So that gets pretty good, eh?\n", "\n", "\n", "But looking back at the definition in Joy, it doesn't seem easy to directly apply this technique to Joy code:\n", "\n", " Ft == [over] dip *\n", " Fb == [[sqr] dip 2 //] dip\n", " Fw == [pop odd] [Ft] [] ifte Fb\n", " F == 1 [pop] [Fw] while popopd\n", "\n", "\n", "But a direct translation of the Python code..?\n", "\n", "\n", " F == [\n", " [[0 =] [pop 1]]\n", " [[1 =] []]\n", " [_F.0]\n", " ] cond\n", "\n", " _F.0 == dup 2 // [\n", " [[0 =] [pop 1]]\n", " [[pop odd] _F.1]\n", " [_F.2]\n", " ] cond\n", "\n", " _F.1 == [1 =] [pop [dup dup * *]] [popd F [dupdip over * *] cons] ifte\n", " _F.2 == [1 =] [pop [dup *]] [popd F [i dup *] cons] ifte\n", "\n", "\n", "Try it:\n", "\n", " 5 F\n", " 5 [ [[0 =] [pop 1]] [[1 =] []] [_F.0] ] cond\n", " 5 _F.0\n", " 5 dup 2 // [ [[0 =] [pop 1]] [[pop odd] _F.1] [_F.2] ] cond\n", " 5 5 2 // [ [[0 =] [pop 1]] [[pop odd] _F.1] [_F.2] ] cond\n", "\n", " 5 2 [ [[0 =] [pop 1]] [[pop odd] _F.1] [_F.2] ] cond\n", " 5 2 _F.1\n", " 5 2 [1 =] [popop [dup dup * *]] [popd F [dupdip over * *] cons] ifte\n", " 5 2 popd F [dupdip over * *] cons\n", " 2 F [dupdip over * *] cons\n", "\n", " 2 F [dupdip over * *] cons\n", "\n", " 2 F\n", " 2 [ [[0 =] [pop 1]] [[1 =] []] [_F.0] ] cond\n", " 2 _F.0\n", " 2 dup 2 // [ [[0 =] [pop 1]] [[pop odd] _F.1] [_F.2] ] cond\n", " 2 2 2 // [ [[0 =] [pop 1]] [[pop odd] _F.1] [_F.2] ] cond\n", " 2 1 [ [[0 =] [pop 1]] [[pop odd] _F.1] [_F.2] ] cond\n", " 2 1 _F.2\n", " 2 1 [1 =] [popop [dup *]] [popd F [i dup *] cons] ifte\n", " 2 1 popop [dup *]\n", " [dup *]\n", "\n", "\n", " 2 F [dupdip over * *] cons\n", " [dup *] [dupdip over * *] cons\n", " [[dup *] dupdip over * *]\n", "\n", "And here it is in action:\n", "\n", " 2 [[dup *] dupdip over * *] i\n", " 2 [dup *] dupdip over * *\n", " 2 dup * 2 over * *\n", " 2 2 * 2 over * *\n", " 4 2 over * *\n", " 4 2 4 * *\n", " 4 8 *\n", " 32\n", "\n", "\n", "\n", "So, it works, but in this case the results of the partial evaluation are more elegant.\n", "\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Try it with `hylomorphism()`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def hylomorphism(c, F, P, G):\n", " '''Return a hylomorphism function H.'''\n", "\n", " def H(a):\n", " if P(a):\n", " result = c\n", " else:\n", " b, aa = G(a)\n", " result = F(b, H(aa))\n", " return result\n", "\n", " return H" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### First, curry\n", "\n", "With abuse of syntax:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def hylomorphism(c):\n", " return lambda F: lambda P: lambda G: lambda a: (\n", " if P(a):\n", " result = c\n", " else:\n", " b, aa = G(a)\n", " result = F(b)(H(aa))\n", " return result\n", " )\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### lambda lowering\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def hylomorphism(c):\n", " def r(a):\n", " def rr(P):\n", " if P(a):\n", " return lambda F: lambda G: c\n", " return lambda F: lambda G: (\n", " b, aa = G(a)\n", " return F(b)(H(aa))\n", " )\n", " return rr\n", " return r\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### expression lifting\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def hylomorphism(c):\n", " def r(a):\n", " def rr(P):\n", " def rrr(G):\n", " if P(a):\n", " return lambda F: c\n", " b, aa = G(a)\n", " H = hylomorphism(c)(aa)(P)(G)\n", " return lambda F: F(b)(H(F))\n", " return rrr\n", " return rr\n", " return r\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### quoted\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def hylomorphism(c):\n", " def r(a):\n", " def rr(P):\n", " def rrr(G):\n", " if P(a):\n", " return \"lambda F: %s\" % (c,)\n", " b, aa = G(a)\n", " H = hylomorphism(c)(aa)(P)(G)\n", " return \"lambda F: F(%(b)s)((%(H)s)(F))\" % locals()\n", " return rrr\n", " return rr\n", " return r\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hylomorphism(0)(3)(lambda n: n == 0)(lambda n: (n-1, n-1))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def F(a):\n", " def _F(b):\n", " print a, b\n", " return a + b\n", " return _F\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "F(2)(3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "eval(hylomorphism(0)(5)(lambda n: n == 0)(lambda n: (n-1, n-1)))(F)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "eval(hylomorphism([])(5)(lambda n: n == 0)(lambda n: (n-1, n-1)))(lambda a: lambda b: [a] + b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hylomorphism(0)([1, 2, 3])(lambda n: not n)(lambda n: (n[0], n[1:]))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hylomorphism([])([1, 2, 3])(lambda n: not n)(lambda n: (n[1:], n[1:]))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "eval(hylomorphism([])([1, 2, 3])(lambda n: not n)(lambda n: (n[1:], n[1:])))(lambda a: lambda b: [a] + b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def hylomorphism(c):\n", " return lambda a: lambda P: (\n", " if P(a):\n", " result = lambda F: lambda G: c\n", " else:\n", " result = lambda F: lambda G: (\n", " b, aa = G(a)\n", " return F(b)(H(aa))\n", " )\n", " return result\n", " )\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def hylomorphism(c):\n", " return lambda a: (\n", " lambda F: lambda P: lambda G: c\n", " if P(a) else\n", " lambda F: lambda P: lambda G: (\n", " b, aa = G(a)\n", " return F(b)(H(aa))\n", " )\n", " )\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def hylomorphism(c):\n", " return lambda a: lambda G: (\n", " lambda F: lambda P: c\n", " if P(a) else\n", " b, aa = G(a)\n", " lambda F: lambda P: F(b)(H(aa))\n", " )\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.15" } }, "nbformat": 4, "nbformat_minor": 2 }