I just started learning Haskell and I can't seem to find a good solution to create a list conditionally.
Basically, what I want is to do list comprehension with an if/else
but without the else
part. I am certain this is possible, I guess I am just using the wrong keywords on my googling quest.
A very stupid example in Python which I want to Haskellize:
[x for x in range(11) if x > 5]
In Haskell, as far as I understand we cannot omit else
blocks like I did in the Python example. How should I do something like this? Does something like nothing exists which I can add to the else
-block in list comprehension, like so:
[if x > 5 then x else Nothing | x <- [0..10]]
I actually came across Nothing in Haskell, though I haven't figure it out yet. It certainly doesn't seem to do what I hoped. Basically I don't want an else
in my list comprehension, but if it's a necessary evil I want to insert nothing in the else
block.
I can think of a bunch of hacks to get similar functionality very inefficiently:
filter
the list after creating it, e.g. filter (>5) [0..10]
concat
them, e.g. concat [if x > 5 then [x] else [] | x <- [0..10]]
These ideas all seem really ugly, though.
Ofcourse in practice I don't want to create conditional lists with such trivial conditions.
List comprehensions are faster than for loops to create lists. But, this is because we are creating a list by appending new elements to it at each iteration.
A list comprehension is a syntactic construct available in some programming languages for creating a list based on existing lists. It follows the form of the mathematical set-builder notation (set comprehension) as distinct from the use of map and filter functions.
You can add an if statement at the end of a list comprehension to return only items which satisfy a certain condition. For example, the code below returns only the numbers in the list that are greater than two.
Use this:
Prelude> [x | x <- [0..10], x > 5]
[6,7,8,9,10]
In Haskell list comprehensions, the "source" expression and all the filters/ifs are "siblings", i.e. there's not much syntactic distinction between them, unlike in Python. So
<expr1> for <source_expr> if <cond_expr>
is just this in Haskell:
[<expr1> | <source_expr>, <cond_expr>, ...]
(source_expr
being x in range(0, 10)
in Python or x <- [0..9]
in Haskell)
and you can have as many "source" and "filter" expressions in a Haskell list comprehension as you like.
This also means that you can write stuff in a style more similar to the mathematical notation; consider:
{ x : x ∈ [0, 10), x > 5 }
and see how the Haskell version is almost the same, compared to the Python one, which looks much more procedural/imperative.
This also works out trivially without any need for additional syntax/constructs with multiple "source" expressions:
Prelude> [(x, y) | x <- [0..10], y <- [10..20], y - x < 5]
[(6,10),(7,10),(7,11),(8,10),(8,11),(8,12),(9,10),(9,11),(9,12),(9,13),(10,10),(10,11),(10,12),(10,13),(10,14)]
In Python you would have to have what looks like a nested list comprehension, however Haskell still just sticks to the mathematical approach/notation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With