{"id":1791,"date":"2012-06-10T20:58:34","date_gmt":"2012-06-11T00:58:34","guid":{"rendered":"http:\/\/scientopia.org\/blogs\/goodmath\/?p=1791"},"modified":"2012-06-10T20:58:34","modified_gmt":"2012-06-11T00:58:34","slug":"a-neat-trick-with-partial-evalutors","status":"publish","type":"post","link":"http:\/\/www.goodmath.org\/blog\/2012\/06\/10\/a-neat-trick-with-partial-evalutors\/","title":{"rendered":"A Neat Trick with Partial Evalutors"},"content":{"rendered":"<p> This is something I was talking about with a coworker today, and I couldn&#8217;t quickly find a friendly writeup of it online, so I decided to write my own. (Yes, we do have a lot of people who enjoy conversations like this at foursquare, which is one of the many reasons that it&#8217;s such a great place to work. And we are hiring engineers! Feel free to get in touch with me if you&#8217;re interested, or just check our website!)<\/p>\n<p> Anyway &#8211; what we were discussing was something called <em>partial evaluation<\/em> (PE).  The idea of PE is almost like an eager form of currying. Basically, you have a two parameter function, f(x, y). You know that you&#8217;re going to invoke it a bunch of times with the same value of x, but different values of y. So what you want to do is create a new function, f<sub>x<\/sub>(y), which evaluates <em>as much as possible<\/em> of f using the known parameter.<\/p>\n<p> It&#8217;s often clearer to see it in programmatic form. Since these days, I pretty much live Scala, I&#8217;ll use Scala syntax. We can abstractly represent a program as an object which can be run with a list of arguments, and which returns some value as its result.<\/p>\n<pre>\ntrait Program {\n  def run(inputs: List[String]): String\n}\n<\/pre>\n<p> If that&#8217;s a program, then a partial evaluator would be:<\/p>\n<pre>\nobject PartialEvaluator {\n  def specialize(prog: Program, knownInputs: List[String]): Program = {\n     ...\n  }\n}\n<\/pre>\n<p>  What it does is take and program and a partial input, and returns a <em>new<\/em> program, which is the original program, specialized for the partial inputs supplied to the partial evaluator. So, for example, imagine that you have a program like:<\/p>\n<pre>\nobject Silly extends Program {\n  def run(inputs: List[String]): String = {\n    val x: Int = augmentString(inputs[0]).toInt\n    val y: Int = augmentString(inputs[0]).toInt\n    if (x % 2 == 0) {\n\t  (y * y).toString\n    } else {\n\t  ((y+1)*(y+1)).toString\n    }\n  }\n}\n<\/pre>\n<p> This is obviously a stupid program, but it&#8217;s good for an example, because it&#8217;s so simple. If we&#8217;re going to run <code>Silly<\/code> a bunch of times with <code>1<\/code> as the first parameter, but with different second parameters, then we could generate a specialized version of <code>Silly<\/code>:<\/p>\n<pre>\n   val sillySpecialOne = PartialEvaluator.specialize(Silly, List(\"1\"))\n<\/pre>\n<p> Here&#8217;s where the interesting part comes, where it&#8217;s really different from<br \/>\ncurrying. A partial evaluator <em>evaluates<\/em> everything that it<br \/>\npossibly can, given the inputs that it&#8217;s supplied. So the value produced by the specializer would be:<\/p>\n<pre>\nobject Silly_1 extends Program {\n  def run(inputs: List[String]): String = {\n    val y: Int = augmentString(inputs[0]).toInt\n    ((y+1)*(y+1)).toString\n  }\n}\n<\/pre>\n<p> This can be a really useful thing to do. It can turn in to a <em>huge<\/em><br \/>\noptimization. (Which is, of course, why people are interested in it.) In compiler terms, it&#8217;s sort of like an uber-advanced form of constant propagation. <\/p>\n<p> But the cool thing that we were talking about is going a bit meta. Suppose that you run a partial evaluator on a programming language interpreter?<\/p>\n<pre>\nobject MyInterpreter extends Program {\n  def run(inputs: List[String]): String = {\n    val code = inputs[0]\n    val inputsToCode = inputs.tail\n    interpretProgram(code, inputsToCode)\n  }\n\n  def interpretProgram(code: String, inputs: List[String]): String = {\n     ...\n  }\n}\n<\/pre>\n<p> We can run our partial evaluator to generate a version of the interpreter that&#8217;s specialized for the code that the interpreter is supposed to execute:<\/p>\n<ol>\n<li> We have an interpreter for language M, written in language L.<\/li>\n<li> We have a partial evaluator for language L.<\/li>\n<li> We run the partial evaluator on the interpreter, with a program<br \/>\n      written in M that we want to interpret:<br \/>\n      <code>PartialEvaluator.specialize(M_Interpreter, M_Code)<\/code>.\n\t<\/li>\n<li> The partial evaluator produces a program written in L.<\/li>\n<\/ol>\n<p> So the partial evaluator took a program written in M, and transformed it into a program written in L!<\/p>\n<p> We can go a step further &#8211; and generate an M to L compiler. How? By running the partial evaluator <em>on itself<\/em>. That is, run the partial<br \/>\nevaluator like this: <code>PartialEvaluator.specialize(PartialEvaluator, M_Interpreter)<\/code>.  The result is a program which takes an M program as<br \/>\ninput, and generates an L program: that is, it&#8217;s an M to L compiler!<\/p>\n<p> We can go yet <em>another<\/em> step, and turn the partial evaluator into a<br \/>\n\tcompiler generator: <code>PartialEvaluator(PartialEvaluator,<br \/>\n\t\t                                      List(source(PartialEvalutor)))<\/code>. What we get is a program which takes an interpreter written in L, and generates a compiler from it. <\/p>\n<p> It&#8217;s possible to actually generate <em>useful<\/em> tools this way. People have actually implemented Lisp compilers this way! For example, you can see someone do a simple version <a href=\"http:\/\/wry.me\/misc\/peval.html\">here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is something I was talking about with a coworker today, and I couldn&#8217;t quickly find a friendly writeup of it online, so I decided to write my own. (Yes, we do have a lot of people who enjoy conversations like this at foursquare, which is one of the many reasons that it&#8217;s such a [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[54],"tags":[],"class_list":["post-1791","post","type-post","status-publish","format-standard","hentry","category-programming"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p4lzZS-sT","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/1791","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/comments?post=1791"}],"version-history":[{"count":0,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/posts\/1791\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/media?parent=1791"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/categories?post=1791"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.goodmath.org\/blog\/wp-json\/wp\/v2\/tags?post=1791"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}