<div class="gmail_quote">On Sat, Jan 14, 2012 at 1:38 PM, Paul Moore <span dir="ltr"><<a href="mailto:p.f.moore@gmail.com">p.f.moore@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div class="im">On 14 January 2012 19:24, Guido van Rossum <<a href="mailto:guido@python.org">guido@python.org</a>> wrote:<br>
> But Paul, aren't you missing the fact that for the algorithms that Annie and<br>
> her students want to write, the "witness" concept is essential? I.e. they<br>
> can't just use any(P(x) for x in xs) because if it returns True, they want<br>
> to know the x that made P(x) be true. Her ! notation is a (perhaps<br>
> unpythonic) attempt at exporting this witness from the quantification.<br>
<br>
</div>Fair point. I was thinking that common cases worked with any(), and<br>
more complex cases that needed a witness would be sufficiently rare<br>
that the extra verbosity would (a) not be a huge burden, and (b) help<br>
to make the intent clearer.<br>
<div class="im"><br>
>> >  while some (!slot_num,p1) in decisions:<br>
>> >     if some (!slot_num,p2) in proposals has p2 != p1:<br>
>> >        propose(p2)<br>
>> >     perform(p1)<br>
</div>[...]<br>
<div class="im">>> Can I suggest you write your example out in Python that works today,<br>
>> and then show how it looks with your proposed syntax alongside? If you<br>
>> can't find the "best" way of writing it in existing Python, just write<br>
>> it however works, no need to try to make it compact, or elegant.<br>
>> There'll be plenty of people here who will show you how to write<br>
>> idiomatic Python versions of what you post :-)<br>
><br>
> Actually she gave one in her first post. Here it is again:<br>
<br>
</div>I'm sorry about that! I got confused part-way through the original<br>
post and skimmed from there, and then didn't go back and reread it in<br>
the context of the follow-up, so I missed the example. My mistake.<br>
<div class="im"><br>
>        while {p1 for (s0,p1) in decisions if s0==slot_num}:<br>
>           p1 = {p1 for (s0,p1) in decisions if s0==slot_num}.pop()<br>
>           for p2 in {p2 for (s0,p2) in proposals if s0==slot_num if p2 != p1}:<br>
><br>
> Note that the set {p1 for (s0,p1) in decisions if s0==slot_num} is computed<br>
> twice, once to decide whether to stop, and then again to compute the witness<br>
> (p1). Obviously this is inefficient, and that's what she's after.<br>
<br>
</div>Agreed, that's inefficient, and it also violates DRY - I can easily<br>
imagine those two lines getting out of sync after a while...<br></blockquote><div><br>Actually it's worse. neither expression needs to compute the full set -- they only need to iterate until the first match.<br> </div>

<blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="im">
> To make<br>
> this same code more efficient in Python, you'd have to do the following,<br>
> which is natural for us programmers (since we're so used to working around<br>
> limitations and inefficiencies in the systems we work with) but unnatural<br>
> for mathematicians, who count to infinity at the drop of a hat:<br>
<br>
</div>Hmm, I have an aversion to languages (or constructs) based around<br>
theoretical principles. Blame a couple of encounters with Haskell a<br>
few years ago. I lost. :-)</blockquote><div><br>In my case the jury is still out, but I'm not worried about Haskell ever overtaking Python. :-)<br><br>FWIW, comprehensions also come from these theoretical principles, so it's not all bad...<br>

 </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">But it tends to be the over-compressed<br>
syntax rather than the ideas that I'm particularly allergic to.<br>
<div class="im"><br>
> while True:<br>
>   temp = {p1 for (s0,p1) in decisions if s0==slot_num}<br>
>   if not temp:<br>
>     break<br>
>   p1 = temp.pop()<br>
><br>
>   for p2 in {p2 for (s0,p2) in proposals if s0==slot_num if p2 != p1}:<br>
>     <whatever><br>
<br>
</div>Point taken. On the other hand, if (x := val) was an expression form<br>
of assignment, like C's assignment, you could write<br>
<br>
while temp := {p1 for (s0,p1) in decisions if s0==slot_num}:<br>
  p1 = temp.pop()<br>
<br>
  for s2 ...<br>
<br>
which is to my mind as succinct, and clearer to a non-mathematician,<br>
as your proposal below (and Annie's proposal). It also builds off a<br>
much more commonly requested feature :-)<br>
<br>
Actually,<br>
<br>
while any(p1 := p for (s,p) in decisions if s == slot_num):<br>
  for s2 ...<br>
<br>
works, and is just as short as your proposal or Annie's.<br></blockquote><div><br>Yeah, and it also avoids computing the elements of the set beyond the first.<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">


<div class="im">> The 5 tedious lines from "while" through "pop()" would be collapsed into a<br>
> single line if you could write<br>
><br>
>   while some s0, p1 in decisions if s0 == slot_num:<br>
><br>
>   for p2 in {p2 for (s0,p2) in proposals if s0==slot_num if p2 != p1}:<br>
>     <whatever><br>
><br>
> TBH I'm not sure what the !slot_num notation is for -- it appears that<br>
><br>
>   while some (!slot_num, p1) in decisions:<br>
><br>
> is equivalent in Annie's proposal to<br>
><br>
>   while some s0, p1 in decisions if s0 == slot_num:<br>
><br>
> but I'm not sure and it doesn't feel necessary to me.<br>
<br>
</div>Yes, I think that's right. It looks like the idea comes from the<br>
concept of unification in logic languages (and the ! notation means<br>
"don't unify this value, but rather treat it as a fixed value that<br>
must match"). Thanks for your analysis, by the way, I think understand<br>
the proposal a lot better now.<br></blockquote><div><br>And thanks for the link with logic languages, that's an area I know even less about...<br> </div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">


So, going back to what Annie was referring to, there seem to be three<br>
key concepts:<br>
<br>
Quantifications, which are covered in Python by any() and all()<br>
Capturing a "witness", which can be done using assignment-as-expression<br>
Tuple matching, which you have shown can be handled using tuple<br>
unpacking plus the generator expression if clause, but could probably<br>
gain from a more compact notation.<br></blockquote><div><br>I'm not sure we need a new construct for tuple matching. Witness capturing seems the most important missing feature here.<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">


BTW, as I'm sure everyone knows, you can simulate assignment-as-expression with<br>
<br>
def asgn(o, val):<br>
  o.ans = val<br>
  return val<br>
<br>
>>> any(asgn(c,x) for x in (1,2,3) if x%2 == 0)<br>
True<br>
>>> c.ans<br>
<div class="im">2<br></div></blockquote><div><br>Eew. :-(<br> <br></div><blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class="im">
> Also note that SOME and EACH quantifiers were present in ABC (Python's<br>
> predecessor: <a href="http://homepages.cwi.nl/%7Esteven/abc/qr.html#TESTS" target="_blank">http://homepages.cwi.nl/~steven/abc/qr.html#TESTS</a>); I dropped<br>
> them for simplicity, not because I didn't like them. If we wanted to we<br>
> could have them back (except for the problems of introducing new keywords).<br>
<br>
</div>One day, I really must read up on ABC.<span class="HOEnZb"></span><br></blockquote></div><br>Just follow the above link and scroll to the top. :-)<br clear="all"><br>-- <br>--Guido van Rossum (<a href="http://python.org/~guido">python.org/~guido</a>)<br>