In ghci, I wrote:
let x = do
i <- [1..5]
j <- [2..4]
return i
Expected result:
[1,2,3,4,5]
Actual result:
[1,1,1,2,2,2,3,3,3,4,4,4,5,5,5]
I don't understand the logic behind that output. I think the reason might be something about monad, but I am very new to functional programming, I wish someone could explain it a little bit.
I've also tried the equavalent form in List-comprehension and the result is the same, which means there is something basic I misunderstood here.
I've also tried the equavalent form in List-comprehension and the result is the same
Good idea. It so happens that for lists, do
notation does exactly the same as list comprehensions. (In fact, there's a syntactic extension that allows you to use list-comprehension notation for any monad, like you can use do
notation for any monad.)
So, you're asking why [a | a<-[0,1], b<-[2,3]]
gives [0,0,1,1]
instead of [0,1]
. The way this looks surprising is if you think about list comprehensions as set comprehensions like you'd find in maths. But lists aren't sets, though Haskellers do often use lists as a makeshift stand-in for sets. If lists comprehensions acted as set comprehension, then
[x | x <- [0,1,0]]
should also yield only [0,1]
as its result (or at least, it should yield the same result as [x|x<-[0,1]]
does).
In general this sort of weeding-out-duplicates requires equality checks, and if you want to make it efficient also either an ordering or a hashing method. Lists don't do any such thing, so if you want set-like behaviour you should use a set-implementing data structure. Set
and HashSet
are the most common.