1

[x:ys | x<-[1,2], ys<-[]]

above code outputs []. I thought it should output [1,2].

So what am I get wrong with Haskell evaluation?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
anru
  • 1,335
  • 3
  • 16
  • 31
  • 2
    Imagine that the two arrows represent nested for loops; the outer one over `xs`, the inner one over `ys`. The thing to the left of the pipe is the loop body. – Sebastian Redl Mar 11 '18 at 21:58
  • @Sebastian Redl, can you move your comment to answer section? – anru Mar 11 '18 at 22:03
  • 1
    If you're just trying to concatenate two lists, you can do `[1, 2] ++ []`, which yields the expected `[1, 2]`. – Asad Saeeduddin Mar 11 '18 at 22:20
  • 1
    `{ for each x in [1,2]: { for each ys in []: yield (x:ys) } }` == `{ { for each ys in []: yield (1:ys)} ; { for each ys in []: yield (2:ys)} }` == `{ for none: yield ... } ; { for none: yield ... } }` == `{none ; none }` == `none`. – Will Ness Mar 11 '18 at 23:20
  • ys in the result is not a list. Try ys<-[[]] ] to produce a list in x:ys -- it will yield x, that is x:[] – fp_mora Mar 15 '18 at 02:43

2 Answers2

3

There are two problems with your expectation:

  1. x:ys always creates a new list; x:[] == [x], not x:[] == x.
  2. Even if x:[] == x, the fact remains that ys <- [] does not assign the name ys to the empty list; it assigns ys to a value contained in the empty list (and of course, there is no such value to assign to ys).

You could change ys <- [] to ys <- [[]], in which case you would get

> [x:ys | x<-[1,2], ys<-[[]]]
[[1], [2]]

but if you want [1,2], the trivial list comprehension would simply be

> [x | x <- [1,2]]
[1,2]

with no other list involved, because you don't want a list of lists as your answer.

chepner
  • 497,756
  • 71
  • 530
  • 681
2

List comprehensions express nested loops:

[x:ys | x<-[1,2], ys<-[]]
 ==
do { x<-[1,2] ; do { ys<-[] ; return (x:ys) } }
 ==
{ for each x in [1,2]: { for each ys in []: yield (x:ys) } }
 == 
{ { for each ys in []: yield (1:ys) }     
; { for each ys in []: yield (2:ys) }     
}
 == 
{ { for none: yield ... } ; { for none: yield ... } }
 == 
{ none ; none }
 == 
none.

This is reminiscent of matrix multiplication:

join [ {- for 1: -}  [ a,b,c   ],       [  1a, 1b, 1c,
       {- for 2: -}  [ d,e     ],   =      2d, 2e,
       {- for 3: -}  [ f,g,h,i ],          3f, 3g, 3h, 3i
        ]                                                 ]

Thus if the list produced for each element of the first list is empty, the total list is empty as well, because concat [ [], [], [] ] == [].

See also: How does the List monad work in this example?

Will Ness
  • 70,110
  • 9
  • 98
  • 181