<div dir="ltr">Hi all,<div><br></div><div>If we want this it might be interesting to investigate what the Scheme community</div><div>has been doing, since they have had this (under the name "promises") for many years.</div><div><br></div><div>Basically:</div><div>  Scheme: (delay expr) </div><div>  <=> </div><div> proposed Python: delayed: expr</div><div><br></div><div>The Scheme community has experimented with what they call "auto-forcing",</div><div>i.e. a promise can be given to any primitive operation and is then forced.</div><div>However this has not caught on. Possibly for a good reason ;-)</div><div>(My gut feeling: too much magic. Explicit is better than implicit.)</div><div><br></div><div>Note that Racket/PLT Scheme has also "lazy" in addition to "delay".</div><div>The rationale for this is given in:</div><div><br></div><div>"How to add laziness to a strict language without even being odd",</div><div> Philip Wadler, Walid Taha, David MacQueen </div><div><a href="https://www.researchgate.net/publication/2646969_How_to_Add_Laziness_to_a_Strict_Language_Without_Even_Being_Odd">https://www.researchgate.net/publication/2646969_How_to_Add_Laziness_to_a_Strict_Language_Without_Even_Being_Odd</a><br></div><div> </div><div>It would be good to read and consider this before we reinvent the square wheel ;-)</div><div><br></div><div>Stephan</div></div><div class="gmail_extra"><br><div class="gmail_quote">2017-02-17 10:14 GMT+01:00 David Mertz <span dir="ltr"><<a href="mailto:david.mertz@gmail.com" target="_blank">david.mertz@gmail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto">Agreed. But there might be cases where something occurring at most one—at some unspecified time—is desirable behavior. In general though, I think avoiding side effects should be programming recommendations, not anything enforced.<div dir="auto"><br></div><div dir="auto">This model isn't really so different from what we do with asyncio and its "call soon" indeterminate order.</div></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Feb 17, 2017 1:07 AM, "Joseph Jevnik" <<a href="mailto:joejev@gmail.com" target="_blank">joejev@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Even with the new syntax I would highly discourage delaying a function with observable side effects. It would make reasoning about the behavior of the program very difficult and debugging becomes much harder.<br></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 17, 2017 at 3:31 AM, David Mertz <span dir="ltr"><<a href="mailto:mertz@gnosis.cx" target="_blank">mertz@gnosis.cx</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto">I had forgotten about Daisy! It's an interesting project too. The behavior of 'autodask()' is closer to what I'd want in new syntax than is plain dask.delayed(). I'm not sure of all the corners. But is definitely love to have it for expressions generally, not only pure functions.</div><div class="m_1940918951664728217m_5506461371736525125HOEnZb"><div class="m_1940918951664728217m_5506461371736525125h5"><div class="gmail_extra"><br><div class="gmail_quote">On Feb 17, 2017 12:03 AM, "Joseph Jevnik" <<a href="mailto:joejev@gmail.com" target="_blank">joejev@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">You can let dask "see" into the function by entering it and wrapping all of the operations in `delayed`; this is how daisy[0] builds up large compute graphs. In this case, you could "inline" the identity function and the delayed object would flow through the function and the call to identity never makes it into the task graph.<br><br>[0] <a href="http://daisy-python.readthedocs.io/en/latest/appendix.html#daisy.autodask" target="_blank">http://daisy-python.readthedoc<wbr>s.io/en/latest/appendix.html#d<wbr>aisy.autodask</a><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Feb 17, 2017 at 2:26 AM, David Mertz <span dir="ltr"><<a href="mailto:mertz@gnosis.cx" target="_blank">mertz@gnosis.cx</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>On Thu, Feb 16, 2017 at 11:15 PM, David Mertz <span dir="ltr"><<a href="mailto:mertz@gnosis.cx" target="_blank">mertz@gnosis.cx</a>></span> wrote:<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div><span style="font-size:11.2px"><font face="arial, helvetica, sans-serif">This also means that a 'delayed' object needs to be idempotent.  So</font></span></div><div><span style="font-size:11.2px"><font face="arial, helvetica, sans-serif"><br></font></span></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><span style="font-size:11.2px"><font face="monospace, monospace">x = delayed 2+2</font></span></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><span style="font-size:11.2px"><font face="monospace, monospace">y = delayed x</font></span></div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><span style="font-size:11.2px"><font face="monospace, monospace">z = delayed delayed delayed y</font></span></div></blockquote><font face="arial, helvetica, sans-serif"><span style="font-size:11.2px"><br></span></font><div><font face="arial, helvetica, sans-serif"><span style="font-size:11.2px">Wrapping more delays around an existing delayed object should probably just keep the same object rather than "doubly delaying" it.  If there is some reason to create separate delayed objects that isn't occurring to me, evaluating 'z' would still go through the multiple evaluation levels until it got to a non-delayed value.</span></font></div></div></blockquote><div><br></div></span><div>This is sort of like how iterators "return self" and 'it = iter(it)'.</div><div><br></div><div>In the case of Dask, wrapping more delayed objects creates layers of these lazy objects.  But I think it has to because it's not part of the syntax.  Actually, I guess Dask could do graph reduction without actual computation if it wanted to.  But this is the current behavior:</div><div><br></div></div></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">>>> def unchanged(x):</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">...     return x</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">>>> a = delayed(unchanged)(42)</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><span style="font-family:monospace,monospace">>>> a</span><br></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">Delayed('unchanged-1780fed6-f8<wbr>35-4c31-a86d-50015ae1449a')</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><span style="font-family:monospace,monospace">>>> b = delayed(unchanged)(a)</span><br></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><span style="font-family:monospace,monospace">>>> c = delayed(unchanged)(b)</span><br></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><span style="font-family:monospace,monospace">>>> c</span><br></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">Delayed('unchanged-adc5e307-6e<wbr>33-45bf-ad73-150b906e921d')</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><span style="font-family:monospace,monospace">>>> c.dask</span><br></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><span style="font-family:monospace,monospace">{'unchanged-1780fed6-f835-4c31<wbr>-a86d-50015ae1449a': (<function __main__.unchanged>,</span><br></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">  42),</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace"> 'unchanged-adc5e307-6e33-45bf<wbr>-ad73-150b906e921d': (<function __main__.unchanged>,</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">  'unchanged-c3282bc4-bdaa-4148-<wbr>8509-9155cac83ef0'),</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace"> 'unchanged-c3282bc4-bdaa-4148<wbr>-8509-9155cac83ef0': (<function __main__.unchanged>,</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">  'unchanged-1780fed6-f835-4c31-<wbr>a86d-50015ae1449a')}</font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace"><br></font></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><span style="font-family:monospace,monospace">>>> c.compute()</span><br></div></div></div><div class="gmail_extra"><div class="gmail_quote"><div><font face="monospace, monospace">42 </font></div></div></div></blockquote><div class="gmail_extra"><br></div><div class="gmail_extra">Actually Dask <b>cannot</b> know that "unchanged()" is the function that makes no transformation on its one parameter.  From what it can see, it's just a function that does <b>something</b>.  And I guess similarly in the proposed syntax, anything other than a plain name after the 'delayed' would still need to create a new delayed object.  So it's all an edge case that doesn't make much difference.<span><br clear="all"><div><br></div>-- <br><div class="m_1940918951664728217m_5506461371736525125m_-2268619700285641245m_2442990671274612690m_5167032093325660184gmail_signature">Keeping medicines from the bloodstreams of the sick; food <br>from the bellies of the hungry; books from the hands of the <br>uneducated; technology from the underdeveloped; and putting <br>advocates of freedom in prisons.  Intellectual property is<br>to the 21st century what the slave trade was to the 16th.<br></div>
</span></div></div>
</blockquote></div><br></div>
</blockquote></div></div>
</div></div></blockquote></div><br></div>
</blockquote></div></div>
</div></div><br>______________________________<wbr>_________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/<wbr>mailman/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/<wbr>codeofconduct/</a><br></blockquote></div><br></div>