<div dir="ltr"><br><br><div class="gmail_quote">On Sat, Oct 11, 2008 at 8:55 AM, Matthew Naylor <span dir="ltr">&lt;<a href="mailto:mfn-haskell-cafe@cs.york.ac.uk" target="_blank">mfn-haskell-cafe@cs.york.ac.uk</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi Jason,<br>
<br>
I don&#39;t know Python, but let me share some thoughts that you might<br>
find useful.<br>
<br>
First, a few questions about your manual translations. &nbsp;Are your<br>
functions curried? &nbsp;For example, can I partially apply zipWith? &nbsp;Also,<br>
you put a &quot;thunk&quot; around things like &quot;cons(...)&quot; --- should it not be<br>
the arguments to &quot;cons&quot; that are thunked?</blockquote><div><br>I don&#39;t recall if I mentioned this in my original email.&nbsp; My goal is to do automatic translations.&nbsp; So, no you can&#39;t partially apply zipWith, but then that&#39;s because Python doesn&#39;t support partial application.&nbsp; On the other hand, you can easily use a lambda to get around this.&nbsp; So in an automatic translation I would replace partial application with lambdas.&nbsp; This shouldn&#39;t be a problem right?<br>

<br>My rule was to put a thunk around any &quot;Haskell value&quot;.&nbsp; So I put cons cells in thunks and I even wrapped functions in thunks.&nbsp; The exception was that there were quite a few places where I could tell by inspection that a particular value would already be in a thunk.&nbsp; For example, since I require in my translation that putting a value in a cons requires the value to be a thunk then when I pull values out of a cons I already know they are thunks so no need to rewrap them. <br>

<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Now, on to an automatic translation. &nbsp;As you may know already, Haskell<br>
programs can be transformed to &quot;combinator programs&quot; which are quite<br>
simple and easy to work with. &nbsp;Here is what I mean by a &quot;combinator<br>
program&quot;:<br>
<br>
 &nbsp;p ::= d* &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;(a program is a list of combinator definitions)<br>
 &nbsp;d ::= c v* = e &nbsp; &nbsp; &nbsp;(combinator definition)<br>
 &nbsp;e ::= e e &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (application)<br>
 &nbsp; &nbsp; | &nbsp;v &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (variable/argument)<br>
 &nbsp; &nbsp; | &nbsp;c &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (constant: integer literal, combinator name, etc.)<br>
<br>
As an example of a combinator program, here is one that reverses the<br>
list [0,1,2].<br>
<br>
 &nbsp;rev v acc &nbsp; &nbsp; = v acc (rev2 acc)<br>
 &nbsp;rev2 acc x xs = rev xs (cons x acc)<br>
 &nbsp;cons x xs n c = c x xs<br>
 &nbsp;nil n c &nbsp; &nbsp; &nbsp; = n<br>
<br>
 &nbsp;main &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= rev (cons 0 (cons 1 (cons 2 nil))) nil<br>
<br>
This program does not type-check in Haskell! &nbsp;But Python, being<br>
dynamically typed, doesn&#39;t suffer from this problem. :-)</blockquote><div><br>I plan to exploit this in my translations as well.&nbsp; I will assume type checked Haskell programs as input to the translator.<br>&nbsp;</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">

<br>
<br>
A translation scheme, D[], from a combinator definition to a Python<br>
definition might look as follows.<br>
<br>
 &nbsp;D[c v* = e] &nbsp; = &nbsp; def c() : return (lambda v1: ... lambda vn: E[e])<br>
 &nbsp;E[e0 e1] &nbsp; &nbsp; &nbsp;= &nbsp; E[e0] (E[e1])<br>
 &nbsp;E[v] &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= &nbsp; v<br>
 &nbsp;E[c] &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;= &nbsp; c()<br>
<br>
Here is the result of (manually) applying D to the list-reversing program.<br>
</blockquote><div><br>If nil() corresponds to [] in Haskell, then how did you arrive at this definition?&nbsp; As Derek Elkins points out your transformation is a CPS based.&nbsp; So I&#39;m going to guess that c is the continuation and n represents the nil?<br>
</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
 &nbsp;def nil() &nbsp;: return (lambda n: lambda c: n)</blockquote><div><br>This one makes a little bit of sense to me.&nbsp; I see the components of the list, the x and xs, and you apply the continuation to them.&nbsp; What&#39;s going on with n?<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">&nbsp;
 def cons() : return (lambda x: lambda xs: lambda n: lambda c: c(x)(xs))</blockquote><div><br>Now, now this is a getting a bit hard to read :) <br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
 &nbsp;def rev2() : return (lambda acc: lambda x: lambda xs:<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rev()(xs)(cons()(x)(acc)))<br>
 &nbsp;def rev() &nbsp;: return (lambda v: lambda acc: v(acc)(rev2()(acc)))<br>
</blockquote><div>&nbsp;<br>I&#39;m glad I don&#39;t have to maintain code that looks like this :)<br><br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
&nbsp;
 def main() : return (rev() (cons()(0)(<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cons()(1)(<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cons()(2)(<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;nil()))))(nil()))<br>
<br>
The result of main() is a partially-applied function, which python<br>
won&#39;t display. &nbsp;But using the helper<br>
<br>
 &nbsp;def list(f) : return (f([])(lambda x: lambda xs: [x] + list(xs)))<br>
<br>
we can see the result of main():<br>
<br>
 &nbsp;&gt;&gt;&gt; list(main())<br>
 &nbsp;[2, 1, 0]</blockquote><div><br>Cool!<br><br>So, supposing I went with a translation scheme like what you gave.&nbsp; I think I would end up with deeply nested function calls, this is probably very bad for the python run-time.&nbsp; Also, how do I allow Python to then access the Haskell values?&nbsp; I guess your definition of list above is an example of that, but I&#39;m not sure how I&#39;d pull that off in general.<br>
&nbsp;<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
Of course, Python is a strict language, so we have lost Haskell&#39;s<br>
non-strictness during the translation. &nbsp;However, there exists a<br>
transformation which, no matter how a combinator program is evaluated<br>
(strictly, non-strictly, or lazily), the result will be just as if it<br>
had been evaluated non-strictly. &nbsp;Let&#39;s call it N, for &quot;Non-strict&quot; or<br>
&quot;call-by-Name&quot;.</blockquote><div><br>Interesting.<br>&nbsp;<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
<br>
 &nbsp;N[e0 e1] &nbsp; = &nbsp; N[e0] (\x. N[e1])<br>
 &nbsp;N[v] &nbsp; &nbsp; &nbsp; = &nbsp; v (\x. x)<br>
 &nbsp;N[f] &nbsp; &nbsp; &nbsp; = &nbsp; f<br>
<br>
I&#39;ve cheekily introduced lambdas on the RHS here --- they are not<br>
valid combinator expressions! &nbsp;But since Python supports lambdas, this<br>
is not a big worry.</blockquote><div><br>Right, not so bad.&nbsp; My translation was doing the same thing actually.&nbsp; A common thing to see in my code is, x = thunk(lambda: y).<br>&nbsp;</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
NOTE 1: We can&#39;t remove the lambdas above by introducing combinators<br>
because the arguments to the combinator would be evaluated and that<br>
would defeat the purpose of the transformation!</blockquote><div><br>Okay, I get that.<br><br>&nbsp;</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
NOTE 2: &quot;i&quot; could be replaced with anything above --- it is never<br>
actually inspected.</blockquote><div><br>What &quot;i&quot; are you referring to?<br>&nbsp;</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Now, non-strict evaluation is all very well, but what we really want<br>
is lazy evaluation. &nbsp;Let&#39;s take the N transformation, rename it to L<br>
for &quot;Lazy&quot;, and indulge in a side-effecting reference, ML style.</blockquote><div><br>Could you explain this a bit more.&nbsp; I don&#39;t know ML, so the code is a bit hard for me to read, but also I was wondering why you introduced a side-effecting reference?&nbsp; Is that basically the same as my thunk type?<br>
&nbsp;<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><br>
<br>
 &nbsp;L[e0 e1] &nbsp; = &nbsp; L[e0] (let r = ref None in<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;\x. match !r with<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; None -&gt; let b = L[e1] in r := Some b ; b<br>
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Some b -&gt; b)<br>
 &nbsp;L[v] &nbsp; &nbsp; &nbsp; = &nbsp; v (\x. x)<br>
 &nbsp;L[f] &nbsp; &nbsp; &nbsp; = &nbsp; f<br>
<br>
I don&#39;t know enough to define L w.r.t Python.<br>
<br>
I haven&#39;t tried too hard to fully understand your translation, and<br>
likewise, you may not try to fully understand mine! &nbsp;But I thought I&#39;d<br>
share my view, and hope that it might be useful (and correct!) in some<br>
way.</blockquote><div><br>Thanks!<br><br>Jason<br></div></div><br></div>