[Python-ideas] Map-then-filter in comprehensions

Michał Żukowski thektulu.pp at gmail.com
Fri Mar 11 10:29:14 EST 2016


>
>
> But in Haskell, the `where` keyword also considers scoping. That is,
> outside the statement/expression with the `where`, you can't access the
> variables introduced by the where.
>
>
Yes, but I wanted it to be simple and powerful, not necessarily right in
every context.

Even though the `where` looks kind-of-nice, it (at least to me) is also
> a bit confusing with respect to evaluation order. Consider
>
>     [ stripped for idx, line in enumerate(lines) if idx >= 5 or stripped
> where stripped=line.strip() ]
>
> (intended semantics: give me all lines (stripped), but ignore
> any lines that are whitespace-only in the first 5 lines)
>
>     retval = []
>     for idx, line in enumerate(lines):
>         stripped = line.strip()
>         if idx >= 5 or stripped:
>             retval.append(stripped)
>
> now I'm not very sure, but I expect what actually happens is:
>
>     retval = []
>     for idx, line in enumerate(lines):
>         if idx < 5:
>             stripped = line.strip()
>         if idx >= 5 or stripped:
>             retval.append(stripped)
>
> that is, should I read it as
>     (if idx >= 5 or stripped) where stripped=line.strip()
> or
>     if idx >= 5 or (stripped where stripped=line.strip())
>

I've implemented it as "or_test [where_expr]" so the default order is the
same as in:
    (if idx >= 5 or stripped) where stripped=line.strip()

I wanted it to always "scope" left as much as possible - in precedence
order between "lambda" and "... if ... else ..." - but left recursion
forced me to place it after  "... if ... else ..." which can't be used
without brackets in list comprehension "if" filtering.
But one can always control order with brackets, and make it work like in
second example.

For comprehensions, I'd think the 'let' statement might make more sense.
> Abusing Haskell's notation:
>
>     [ stripped | (idx, line) <- zip [0..] lines, let stripped = strip
> line, idx >= 5 || length stripped > 0 ]
>
> Porting this to something Python-ish, it'd be
>
>     [ stripped for idx, line in enumerate(lines) let stripped =
> line.strip() if idx >= 5 or stripped ]
>
> where `let` is a keyword (possibly only applicable in a compexpr). In
> Haskell it's a keyword everywhere, but it has somewhat different
> semantics.
>

I was thinking about "let", but as I said, I think that new keyword should
be more powerful than just filtering in list comprehensions, and in regular
expresions it would look like this:
    if let x=foo() in x:
        print(x)

Which does not look great, and there is problem with "in" keyword that make
this expresion ambiguous.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20160311/2e176d4b/attachment.html>


More information about the Python-ideas mailing list