4 ms·
I dislike the lisp convention of remove-if, remove-if-not, etc. Filter and take isn't much better. The python convention is much nicer: [x for x in foo if x
by sillysaurusx 6y ago
I dislike the lisp convention of remove-if, remove-if-not, etc. Filter and take isn't much better. The python convention is much nicer:
[x for x in foo if x not in y]
Turns out, this can be expressed in Lisp:
(list x for x in foo if x not in y)
I've implemented this into my fork of Lumen that runs on Python. https://github.com/shawwn/pymen https://github.com/shawwn/pymen It feels very nice to use:
> (list x for x in (range 10) if (= (% x 2) 0))
"""
Built-in mutable sequence.
If no argument is given, the constructor creates a new empty list.
The argument must be an iterable if specified.
"""
[0, 2, 4, 6, 8]
>
It wasn't even that ugly to implement. It's ~20 lines: https://github.com/shawwn/pymen/blob/1c191c9e00e73303a6479f8f56ecb0ba84bb1566/macros.l#L27-L55 https://github.com/shawwn/pymen/blob/1c191c9e00e73303a6479f8...
One other neat thing is that the REPL prints out the docstring of the last evaluated thing by default. It makes it nice to explore libraries:
> (import numpy as np)
https://imgur.com/1rpF95y https://imgur.com/1rpF95y
> np.vsplit
https://imgur.com/OjIvTWt https://imgur.com/OjIvTWt
It's like an automatic help() call on the last evaluated thing.
(If anyone happens to try it out, you can get into a REPL by running `rlwrap bin/pymen`, or just `bin/pymen`.)
- garethjrowlands 6y agoFor those that didn't know, Haskell does of course have list comprehensions: [x| x <- foo, not (elem x y)] Here's an example finding consonants: [c| x <- ['a'..'z'], not (elem x) $ "aeiou"]
- dwohnitmok 6y agoHaskell's list comprehensions actually started off as more general monad comprehensions, were later restricted to lists, and are back behind a GHC language pragma.
- centimeter 6y agoNo need for the dollar sign in the second example :) A nice thing about Haskell list comprehensions is they're based on a trivial transformation to monad syntax, which makes it easier to factor out complex list transformations into multiple little bites. I've run into this problem in Python. Also, Python list comprehensions can often behave very unexpectedly due to mutability. Here's an example of the monad syntax: [(x,y) | x <- [1..10], y <- [1..x], odd (x + y)] equiv do x <- [1..10] y <- [1..x] guard $ odd (x + y) return (x,y) Lots of combinatorics problems can be elegantly solved using the list monad like that.
- mypalmike 6y agoExample where Python list comprehensions behave very unexpectedly...?
- PuercoPop 6y agoIt is also ~20 lines in CL http://lisp-univ-etc.blogspot.com/2013/01/real-list-comprehensions-in-lisp.html http://lisp-univ-etc.blogspot.com/2013/01/real-list-comprehe... But list comprehensions suffer from the same problem the author is taking about, they don't compose. Its even worse than CL remove-if variant, where one can reify the filter into a function that can then compose.
- TeMPOraL 6y agoHuh, the syntax can be almost directly spliced into Common Lisp's loop: CL-USER> (let ((foo '(1 2 3)) (y '(2 4))) (loop for x in foo unless (member x y :test #'=) collect x)) ;; -> (1 3) It wouldn't be hard to write a macro that expands your expressions to CL's loop, with a bit of magic to parse the "if ... [not] in ...".
- zoltar 6y agoEven though it's more "Pythonic", I tend to avoid your Python version. I think my favorite way to write that would be: > import whatever > filter(_ not in y, foo) For me it's more readable. To each their own, of course.