views:

314

answers:

4

Looking at comprehensions in Python and Javascript, so far I can't see some of the main features that I consider most powerful in comprehensions in languages like Haskell.

Do they allow things like multiple generators? Or are they just a basic map-filter form?

If they don't allow multiple generators, I find them quite disappointing - why have such things been left out?

+3  A: 

Yes, you can have multiple iterables in a Python list comprehension:

>>> [(x,y) for x in range(2) for y in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]
Triptych
Cool, I'm glad. I'm just wondering why I couldn't find this information easily... none of the examples on Wikipedia or elsewhere seem to include this. Now all I dislike is the syntax compared to Haskell. :) What about Javascript?
RD1
+12  A: 

Python allows multiple generators:

>>> [(x,y,x*y) for x in range(1,5) for y in range(1,5)]
[(1, 1, 1), (1, 2, 2), (1, 3, 3), (1, 4, 4), 
 (2, 1, 2), (2, 2, 4), (2, 3, 6), (2, 4, 8), 
 (3, 1, 3), (3, 2, 6), (3, 3, 9), (3, 4, 12),
 (4, 1, 4), (4, 2, 8), (4, 3, 12), (4, 4, 16)]

And also restrictions:

>>> [(x,y,x*y) for x in range(1,5) for y in range(1,5) if x*y > 8]
[(3, 3, 9), (3, 4, 12), (4, 3, 12), (4, 4, 16)]

Update: Javascript's syntax is similar (results from using the javascript shell on firefox):

var nums = [1, 2, 3, 21, 22, 30];
var s = eval('[[i,j] for each (i in nums) for each (j in [3,4]) if (i%2 == 0)]');
s.toSource();
[[2, 3], [2, 4], [22, 3], [22, 4], [30, 3], [30, 4]]

(For some reason, something about the context stuff is evaluated in in the javascript shell requires the eval indirection to have list comprehensions work. Javascript inside a <script> tag doesn't require that, of course)

Daniel Martin
Cool. Now all Python needs is pattern matching in generators. And to generalize comprehensions beyond sequences to other monads. And er - a typerchecker. :)
RD1
No. Python isn't Haskell. Type checking is against the philosophy of python.
Georg
From what I've read, optional static type checking was seriously considered for Python for a while before being rejected. So, I don't believe it can be that much against the philosophy. And history tells us that languages like Lisp without type checkers do not scale well, even with unit testing. Personally I find it hard to teach my students when they can't rely on the IDE to understand the types of things - static types make programming so much easier when learning to program with a good IDE.
RD1
Nice update. For Javascript this information seemed quite hard to find. And, I guess I was in a lazy mood. :)I was asking partly due to needing to recommend languages for teaching in a non-CS major course for "light programming". I'd still like to recommend F#, but I think Python and Javascript are more likely to go down well with other people.
RD1
The mere fact that static type checking was finally rejected is a sure enough indication that it's not pythonic. One of the main points about Python is dynamism - and not only wrt/ typing. Remember that in Python, you can add/replace/remove attributes and methods at runtime, whether on a per-object or per-instance basis. You can even change the class of an object at runtime FWIW. Even worse - 'class' is a runtime executable statement. Good luck with static type-checking this !-)
bruno desthuilliers
You can emulate anything dynamically typed in a statically typed language just by making library constructs that always return the same "universal" type. It even ends up looking pretty similar to the original code.Building a library that emulates python in a statically typed language is pretty easy. People don't do exactly this, but they do often do similar things when weaker typing is desired. It's really easy.The other way is impossible because there is no type checker.
RD1
By avoiding the type checks in a statically typed language you often get problems because the compiler assumes the type checking is there and useful. In C you typically end up with pointers, and then you do the wrong thing with the wrong pointer and *kablam*.Checking types in Python is trivial should you want to.`assert isinstance(ob, type)`
Lennart Regebro
@Rowan static typing is an optimisation, and shouldn't be necessary to learn how to program. One of the greatest books for learning programming SICP uses scheme.
justinhj
+1  A: 

Add an if statement as well...

>>> [(x,y) for x in range(5) for y in range(6) if x % 3 == 0 and y % 2 == 0]
[(0, 0), (0, 2), (0, 4), (3, 0), (3, 2), (3, 4)]
Peter
+1  A: 

Comprehensions is very powerful in Haskell to a large extent because Haskell is functional, so it makes extremely much sense for them to be. Python is not functional so it makes less sense.

You can make a lot of complex things with comprehensions in Python but it quickly becomes hard to read, thereby defeating the whole purpose (meaning you should do it some other way).

However, as pointed out here, python does allow multiple generators in comprehensions.

Lennart Regebro
Last I heard, one of the strengths of Python is that is it supports functional programming, and embraces things like closures. Is there another way to do the equivalent of a multiple generator comprehension that is more elegant in Python?
RD1
Python has a restricted support for functional programming - mainly due to the fact that Python functions are true objects. It also borrowed a couple constructs from functional languages. But it's still mostly and basically an imperative object-oriented language. Also, the pythonesque definition of "elegance" is *readability*. A multiple generator comprehension is usually way more readable (for the majority of programmers at least) written as a plain old "for" loop.
bruno desthuilliers
@Rowan: Yes, for loops, typically. You also want to look into creating your own generators with `yield` or possibly `__next__`.
Lennart Regebro
Python doesn't support functional programming very well (more than Java, sure), and it doesn't embrace closures so much as give them a brief, limp handshake. Lambdas in Python are relegated to the same second-class-citizen status as for-loops in OCaml.
Chuck