Haskell Monad - How does Monad on list work? - list

In order to understand Monad, I came up with the following definitions:
class Applicative' f where
purea :: a -> f a
app :: f (a->b) -> f a -> f b
class Applicative' m => Monadd m where
(>>|) :: m a -> (a -> m b) -> m b
instance Applicative' [] where
purea x = [x]
app gs xs = [g x | g <- gs, x <- xs]
instance Monadd [] where
(>>|) xs f = [ y | x <-xs, y <- f x]
It works as expected:
(>>|) [1,2,3,4] (\x->[(x+1)])
[2,3,4,5]
I am not sure how it is working though.
For example:
[ y | y <- [[1],[2]]]
[[1],[2]]
How does application (\x->([x+1]) to each list element of [1,2,3] result in [2,3,4] and not [[2],[3],[4]]
Or quite simply my confusion seems to stem from not understanding how this statement [ y | x <-xs, y <- f x] actually works

Wadler, School of Haskell, LYAH, HaskellWiki, Quora and many more describe the list monad.
Compare:
(=<<) :: Monad m => (a -> m b) -> m a -> m b for lists with
concatMap :: (a -> [b]) -> [a] -> [b] for m = [].
The regular (>>=) bind operator has the arguments flipped, but is otherwise just an infix concatMap.
Or quite simply my confusion seems to stem from not understanding how this statement actually works:
(>>|) xs f = [ y | x <- xs, y <- f x ]
Since list comprehensions are equivalent to the Monad instance for lists, this definition is kind of cheating. You're basically saying that something is a Monadd in the way that it's a Monad, so you're left with two problems: Understanding list comprehensions, and still understanding Monad.
List comprehensions can be de-sugared for a better understanding:
Removing syntactic sugar: List comprehension in Haskell
In your case, the statement could be written in a number of other ways:
Using do-notation:
(>>|) xs f = do x <- xs
y <- f x
return y
De-sugared into using the (>>=) operator:
(>>|) xs f = xs >>= \x ->
f x >>= \y ->
return y
This can be shortened (one rewrite per line):
(>>|) xs f = xs >>= \x -> f x >>= \y -> return y -- eta-reduction
≡ (>>|) xs f = xs >>= \x -> f x >>= return -- monad identity
≡ (>>|) xs f = xs >>= \x -> f x -- eta-reduction
≡ (>>|) xs f = xs >>= f -- prefix operator
≡ (>>|) xs f = (>>=) xs f -- point-free
≡ (>>|) = (>>=)
So from using list comprehensions, you haven't really declared a new definition, you're just relying on the existing one. If you wanted, you could instead define your instance Monadd [] without relying on existing Monad instances or list comprehensions:
Using concatMap:
instance Monadd [] where
(>>|) xs f = concatMap f xs
Spelling that out a little more:
instance Monadd [] where
(>>|) xs f = concat (map f xs)
Spelling that out even more:
instance Monadd [] where
(>>|) [] f = []
(>>|) (x:xs) f = let ys = f x in ys ++ ((>>|) xs f)
The Monadd type class should have something similar to return. I'm not sure why it's missing.

Monads are often easier understood with the “mathematical definition”, than with the methods of the Haskell standard class. Namely,
class Applicative' m => Monadd m where
join :: m (m a) -> m a
Note that you can implement the standard version in terms of this, vice versa:
join mma = mma >>= id
ma >>= f = join (fmap f ma)
For lists, join (aka concat) is particularly simple:
join :: [[a]] -> [a]
join xss = [x | xs <- xss, x <- xs] -- xss::[[a]], xs::[a]
-- join [[1],[2]] ≡ [1,2]
For the example you find confusing, you'd have
[1,2,3,4] >>= \x->[(x+1)]
≡ join $ fmap (\x->[(x+1)]) [1,2,3,4]
≡ join [[1+1], [2+1], [3+1], [4+1]]
≡ join [[2],[3],[4],[5]]
≡ [2,3,4,5]

List comprehensions are just like nested loops:
xs >>| foo = [ y | x <- xs, y <- foo x]
-- = for x in xs:
-- for y in (foo x):
-- yield y
Thus we have
[1,2,3,4] >>| (\x -> [x, x+10])
=
[ y | x <- [1,2,3,4], y <- (\x -> [x, x+10]) x]
=
[ y | x <- [1] ++ [2,3,4], y <- [x, x+10]]
=
[ y | x <- [1], y <- [x, x+10]] ++ [ y | x <- [2,3,4], y <- [x, x+10]] -- (*)
=
[ y | y <- [1, 1+10]] ++ [ y | x <- [2,3,4], y <- [x, x+10]]
=
[ y | y <- [1]] ++ [ y | y <- [11]] ++ [ y | x <- [2,3,4], y <- [x, x+10]]
=
[1] ++ [11] ++ [ y | x <- [2,3,4], y <- [x, x+10]]
=
[1, 11] ++ [2, 12] ++ [ y | x <- [3,4], y <- [x, x+10]]
=
[1, 11] ++ [2, 12] ++ [3, 13] ++ [ y | x <- [4], y <- [x, x+10]]
=
[1, 11] ++ [2, 12] ++ [3, 13] ++ [4, 14]
The crucial step is marked (*). You can take it as the definition of what list comprehensions are.
A special case is when the foo function returns a singleton list, like in your question. Then it is indeed tantamount to mapping, as each element in the input list is turned into one (transformed) element in the output list.
But list comprehensions are more powerful. An input element can also be turned conditionally into no elements (working as a filter), or several elements:
[ a, [a1, a2] ++ concat [ [a1, a2], [ a1, a2,
b, ==> [b1] ++ == [b1], == b1,
c, [] ++ [],
d ] [d1, d2] [d1, d2] ] d1, d2 ]
The above is equivalent to
concat (map foo [a,b,c,d])
=
foo a ++ foo b ++ foo c ++ foo d
for some appropriate foo.
concat is list monad's join, and map is list monad's fmap. In general, for any monad,
m >>= foo = join (fmap foo m)
The essence of Monad is: from each entity "in" a "structure", conditionally producing new elements in the same kind of structure, and splicing them in-place:
[ a , b , c , d ]
/ \ | | / \
[ [a1, a2] , [b1] , [] , [d1, d2] ] -- fmap foo = [foo x | x <- xs]
-- = [y | x <- xs, y <- [foo x]]
[ a1, a2 , b1 , d1, d2 ] -- join (fmap foo) = [y | x <- xs, y <- foo x ]

Related

I am struggling to understand how concat is read in Haskell

The code for concat:
concat :: [[a]] -> [a]
concat xss = [x | xs <- xss, x <- xs]
I don't understand how it is being read. How does xss get split into xs and x? Or am I misreading it?
For example, given:
concat [[1,2,3],[4],[5]]
how is [1,2,3,4,5] achieved?
Inside a list comprehension, the bit a <- b means "for each a in b".
So in your case, xs <- xss should read like "for each xs in xss", and then x <- xs should read like "for each x in xs", which is also valid becase xs itself is a list, because xss is a list of lists.
So as the list comprehension unfolds, xs becomes bound first to [1,2,3], then to [4], and then to [5], and within each iteration of xs, x becomes bound to 1, 2, 3, then to 4, and finally to 5.
If we had to make a comparison with imperative programming, we can think of
[ expr | x1 <- list1 , x2 <- list2 , ....]
as a nested for loop accumulating the values resulting from expr in a list, as follows:
result = []
for x1 in list1:
for x2 in list2:
...
result.append(expr)
In you case, we have
result = []
for xs in xss:
for x in xs:
result.append(x)
So, when xss = [[1,2,3],[4],[5]] we have:
xs = [1,2,3]
x = 1 gets appended to the result
x = 2 gets appended to the result
x = 3 gets appended to the result
xs = [4]
x = 4 gets appended to the result
xs = [5]
x = 5 gets appended to the result
The final result is therefore [1,2,3,4,5].
This comparison is not a completely faithful description, since it does not take laziness into account, and Haskell does not really compute the final list by appending data to a mutable list as done above. Perhaps Python's yield and generators would be closer. Still, the comparison above should illustrate the basic mechanism.
Well with the obvious identities,
[ E | P <- (xs ++ ys), Q ] === [ E | P <- xs, Q ] ++ [ E | P <- ys, Q ]
[ x | xs <- [E], x <- xs ] === [ x | x <- E ]
[ x | x <- [E] ] === [E]
we can just follow the code,
concat [[1,2,3], [4], [5]]
= {- by definition of `concat` -}
[x | xs <- [[1,2,3], [4], [5]], x <- xs]
= {- by definition of `++` -}
[x | xs <- [[1,2,3]] ++ [[4], [5]], x <- xs]
= {- by the first identity -}
[x | xs <- [[1,2,3]], x <- xs] ++ [x | xs <- [[4], [5]], x <- xs]
= {- by the second identity -}
[x | x <- [1,2,3] ] ++ [x | xs <- [[4], [5]], x <- xs]
= {- by definition of `++` -}
[x | x <- [1,2,3] ] ++ [x | xs <- [[4]] ++ [[5]], x <- xs]
= {- by the first identity -}
[x | x <- [1,2,3]] ++ [x | xs <- [[4]], x <- xs] ++ [x | xs <- [[5]], x <- xs]
= {- by the second identity -}
[x | x <- [1,2,3]] ++ [x | x <- [4] ] ++ [x | x <- [5] ]
= {- and by the third -}
[x | x <- [1,2,3]] ++ [ 4 ] ++ [ 5 ]
= {- repeating as before -}
[x | x <- [1]] ++ [x | x <- [2]] ++ [x | x <- [3]] ++ [4] ++ [ 5 ]
= {- by the third identity -}
[ 1 ] ++ [ 2 ] ++ [ 3 ] ++ [4] ++ [ 5 ]
= {- by definition of `++` -}
[ 1 , 2 , 3 , 4 , 5 ]
Thus concat, when applied to a list of lists, has the effect of "opening up" and eliminating the inner parentheses in it.
In the process we have also discovered another identity,
[ x | x <- Q ] === Q
which follows from the ones above and the properties of ++, where
[A,B,C,...,Z] === [A] ++ [B] ++ [C] ++ ... ++ [Z]
See also:
An introduction to the theory of lists. Technical Monograph PRG-56, R.S. Bird 1986.

Understanding the list monad [duplicate]

In order to understand Monad, I came up with the following definitions:
class Applicative' f where
purea :: a -> f a
app :: f (a->b) -> f a -> f b
class Applicative' m => Monadd m where
(>>|) :: m a -> (a -> m b) -> m b
instance Applicative' [] where
purea x = [x]
app gs xs = [g x | g <- gs, x <- xs]
instance Monadd [] where
(>>|) xs f = [ y | x <-xs, y <- f x]
It works as expected:
(>>|) [1,2,3,4] (\x->[(x+1)])
[2,3,4,5]
I am not sure how it is working though.
For example:
[ y | y <- [[1],[2]]]
[[1],[2]]
How does application (\x->([x+1]) to each list element of [1,2,3] result in [2,3,4] and not [[2],[3],[4]]
Or quite simply my confusion seems to stem from not understanding how this statement [ y | x <-xs, y <- f x] actually works
Wadler, School of Haskell, LYAH, HaskellWiki, Quora and many more describe the list monad.
Compare:
(=<<) :: Monad m => (a -> m b) -> m a -> m b for lists with
concatMap :: (a -> [b]) -> [a] -> [b] for m = [].
The regular (>>=) bind operator has the arguments flipped, but is otherwise just an infix concatMap.
Or quite simply my confusion seems to stem from not understanding how this statement actually works:
(>>|) xs f = [ y | x <- xs, y <- f x ]
Since list comprehensions are equivalent to the Monad instance for lists, this definition is kind of cheating. You're basically saying that something is a Monadd in the way that it's a Monad, so you're left with two problems: Understanding list comprehensions, and still understanding Monad.
List comprehensions can be de-sugared for a better understanding:
Removing syntactic sugar: List comprehension in Haskell
In your case, the statement could be written in a number of other ways:
Using do-notation:
(>>|) xs f = do x <- xs
y <- f x
return y
De-sugared into using the (>>=) operator:
(>>|) xs f = xs >>= \x ->
f x >>= \y ->
return y
This can be shortened (one rewrite per line):
(>>|) xs f = xs >>= \x -> f x >>= \y -> return y -- eta-reduction
≡ (>>|) xs f = xs >>= \x -> f x >>= return -- monad identity
≡ (>>|) xs f = xs >>= \x -> f x -- eta-reduction
≡ (>>|) xs f = xs >>= f -- prefix operator
≡ (>>|) xs f = (>>=) xs f -- point-free
≡ (>>|) = (>>=)
So from using list comprehensions, you haven't really declared a new definition, you're just relying on the existing one. If you wanted, you could instead define your instance Monadd [] without relying on existing Monad instances or list comprehensions:
Using concatMap:
instance Monadd [] where
(>>|) xs f = concatMap f xs
Spelling that out a little more:
instance Monadd [] where
(>>|) xs f = concat (map f xs)
Spelling that out even more:
instance Monadd [] where
(>>|) [] f = []
(>>|) (x:xs) f = let ys = f x in ys ++ ((>>|) xs f)
The Monadd type class should have something similar to return. I'm not sure why it's missing.
Monads are often easier understood with the “mathematical definition”, than with the methods of the Haskell standard class. Namely,
class Applicative' m => Monadd m where
join :: m (m a) -> m a
Note that you can implement the standard version in terms of this, vice versa:
join mma = mma >>= id
ma >>= f = join (fmap f ma)
For lists, join (aka concat) is particularly simple:
join :: [[a]] -> [a]
join xss = [x | xs <- xss, x <- xs] -- xss::[[a]], xs::[a]
-- join [[1],[2]] ≡ [1,2]
For the example you find confusing, you'd have
[1,2,3,4] >>= \x->[(x+1)]
≡ join $ fmap (\x->[(x+1)]) [1,2,3,4]
≡ join [[1+1], [2+1], [3+1], [4+1]]
≡ join [[2],[3],[4],[5]]
≡ [2,3,4,5]
List comprehensions are just like nested loops:
xs >>| foo = [ y | x <- xs, y <- foo x]
-- = for x in xs:
-- for y in (foo x):
-- yield y
Thus we have
[1,2,3,4] >>| (\x -> [x, x+10])
=
[ y | x <- [1,2,3,4], y <- (\x -> [x, x+10]) x]
=
[ y | x <- [1] ++ [2,3,4], y <- [x, x+10]]
=
[ y | x <- [1], y <- [x, x+10]] ++ [ y | x <- [2,3,4], y <- [x, x+10]] -- (*)
=
[ y | y <- [1, 1+10]] ++ [ y | x <- [2,3,4], y <- [x, x+10]]
=
[ y | y <- [1]] ++ [ y | y <- [11]] ++ [ y | x <- [2,3,4], y <- [x, x+10]]
=
[1] ++ [11] ++ [ y | x <- [2,3,4], y <- [x, x+10]]
=
[1, 11] ++ [2, 12] ++ [ y | x <- [3,4], y <- [x, x+10]]
=
[1, 11] ++ [2, 12] ++ [3, 13] ++ [ y | x <- [4], y <- [x, x+10]]
=
[1, 11] ++ [2, 12] ++ [3, 13] ++ [4, 14]
The crucial step is marked (*). You can take it as the definition of what list comprehensions are.
A special case is when the foo function returns a singleton list, like in your question. Then it is indeed tantamount to mapping, as each element in the input list is turned into one (transformed) element in the output list.
But list comprehensions are more powerful. An input element can also be turned conditionally into no elements (working as a filter), or several elements:
[ a, [a1, a2] ++ concat [ [a1, a2], [ a1, a2,
b, ==> [b1] ++ == [b1], == b1,
c, [] ++ [],
d ] [d1, d2] [d1, d2] ] d1, d2 ]
The above is equivalent to
concat (map foo [a,b,c,d])
=
foo a ++ foo b ++ foo c ++ foo d
for some appropriate foo.
concat is list monad's join, and map is list monad's fmap. In general, for any monad,
m >>= foo = join (fmap foo m)
The essence of Monad is: from each entity "in" a "structure", conditionally producing new elements in the same kind of structure, and splicing them in-place:
[ a , b , c , d ]
/ \ | | / \
[ [a1, a2] , [b1] , [] , [d1, d2] ] -- fmap foo = [foo x | x <- xs]
-- = [y | x <- xs, y <- [foo x]]
[ a1, a2 , b1 , d1, d2 ] -- join (fmap foo) = [y | x <- xs, y <- foo x ]

How to implement a function using bind (>>=)

I wrote a filter function:
f :: (a -> Bool) -> [a] -> [a]
f p xs = case xs of
[] -> []
x : xs' -> if p x
then x : f p xs'
else f p xs'
To understand bind, I want to implement this using bind.
What I was thinking about:
f p xs = xs >>= (\x xs -> if p x then x : f p xs else f p xs)
But I get this error:
* Couldn't match expected type `[a]' with actual type `[a] -> [a]'
* The lambda expression `\ x xs -> ...' has two arguments,
but its type `a -> [a]' has only one
In the second argument of `(>>=)', namely
`(\ x xs -> if p x then x : f p xs else f p xs)'
In the expression:
xs >>= (\ x xs -> if p x then x : f p xs else f p xs)
* Relevant bindings include
xs :: [a] (bound at <interactive>:104:5)
p :: a -> Bool (bound at <interactive>:104:3)
f :: (a -> Bool) -> [a] -> [a] (bound at <interactive>:104:1)
Successfully did it using foldr:
f p xs = foldr (\x xs -> if p x then x : f p xs else f p xs) [] xs
What's going wrong?
To understand bind, i want to implement this as bind.
There is no bind here. The bind is added in case of a do expression. The above is not a do-expression, so there is no bind here.
You can however write this with bind, like:
f p xs = xs >>= \x -> if p x then [x] else []
but this is not a literal mapping of the original function, we simply make use of the instance Monad [] implementation here. Nevertheless, your f is just filter :: (a -> Bool) -> [a] -> [a] here.
To understand bind, first implement the no-op:
id_list xs = concat [ [x] | x <- xs ] = [ y | x <- xs, y <- [x ] ]
Now for the filter, augment it as
filter p xs = concat [ [x | p x] | x <- xs ] = [ y | x <- xs, y <- [x | p x] ]
How is this code using bind, you ask? If we're using MonadComprehensions, it does.
The explicit do-notation re-write is straightforward:
id_list xs = do { x <- xs ; y <- [ x ] ; return y }
filter p xs = do { x <- xs ; y <- [ x | p x] ; return y }
And of course, for lists,
[x] == return x
[x | p x] == if p x then return x else mzero
mzero == []
concat == join
This brings us back to an explicitly recursive way to code filter as
filter p [] = []
filter p (x:xs) = [x | p x] ++ filter p xs
With bind, we think in terms of transforming each element of the list individually, into the list of results (none, one, or several) for that one input element. Your foldr-based code breaks this.
So, the code itself is just
filter_bind p xs = xs >>= (\x -> [x | p x])
because we have
xs >>= f == join (fmap f xs)
== concat (map f xs)
== concat [ f x | x <- xs ]
== foldr (++) []
[ f x | x <- xs ]
with the last snippet corresponding to the explicitly recursive definition above.
See also
How does the List monad work in this example?
Haskell Monad - How does Monad on list work?
etc.

Rewriting zipWith function using list comprehension

I've rewritten the zipWith function using recursion, and now I am trying to rewrite it using list comprehension. I have run into quite a few binding errors and I know that my second line is incorrect. This is the function I have that works like zipWith using recursion:
zipW :: (a -> b -> c) -> [a] -> [b] -> [c]
zipW _ [] _ = []
zipW _ _ [] = []
zipW f (x:xs) (y:ys) = f x y : zipW f xs ys
And this is my attempt to rewrite it as list comprehension:
zipW2 :: (a -> b -> c) -> [a] -> [b] -> [c]
zipW2 f xs ys = [f x y | (x, y) <- zipW2 f xs ys]
I am not sure how to correct the second statement so that it works like zipWith and allows me to choose the operator.
You will need Parallel List Comprehensions extension:
{-# LANGUAGE ParallelListComp #-}
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = [f x y | x <- xs | y <- ys]
The original zipWith has three cases:
when the first list is empty
when the second list is empty
when the neither list is empty
The third case recursively calls zipWith on the tails of the arguments, which does the case analysis again.
In your definition, you only have one case - the list comprehension, so any recursive calls are going to wrap right back to that. And without case analysis, you could loop forever here:
>>> let myZipWith f xs ys = [ f x y | (x,y) <- myZipWith f xs ys ]
>>> myZipWith (,) [] []
^CInterrupted.
Furthermore because you're using f in the recursive call but requiring that the recursive output be a pair, you're placing the implicit requirement that f x y produce a pair:
>>> :t myZipWith
myZipWith :: (t2 -> t3 -> (t2, t3)) -> t -> t1 -> [(t2, t3)]
The solution is to not recurse, but instead to consider each pair directly.
You can use behzad.nouri's solution of enabling the ParallelListComp language extension:
>>> :set -XParallelListComp
>>> let myZipWith f xs ys = [ f x y | x <- xs | y <- ys ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]
ParallelListComp makes the second (and later) vertical pipe characters (|) in a list comprehension legal syntax, stepping through those lists in parallel (zip-like) with earlier lists.
It's good to know how this differs from normal list comprehensions, where you separate each list you draw from with commas. Using commas does nested iteration which is flattened out in the resulting list:
>>> let notZipWith f xs ys = [ f x y | x <- xs, y <- ys ]
>>> notZipWith (+) [1,2,4] [0,10,20]
[1,11,21,2,12,22,4,14,24]
Using the ParallelListComp extension is really just syntatical sugar for the original zipWith, so you may consider it cheating.
You could also just rely on the original zip:
>>> let myZipWith f xs ys = [ f x y | (x,y) <- zip xs ys ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]
But since zip is defined as zipWith (,), that's probably cheating too.
Another way you could go is to use indices:
>>> let myZipWith f xs ys = [ f x y | i <- [0..min (length xs) (length ys) - 1], let x = xs !! i, let y = ys !! i ]
>>> myZipWith (+) [1,2,4] [0,10,20]
[1,12,24]
But this is going to be horrendously inefficient, as !! is a linear-time operation, making myZipWith quadratic, while zipWith is linear:
>>> :set +s
>>> last $ myZipWith (+) (replicate 10000000 1) (replicate 10000000 2)
3
(4.80 secs, 3282337752 bytes)
>>> last $ zipWith (+) (replicate 10000000 1) (replicate 10000000 2)
3
(0.40 secs, 2161935928 bytes)
I'm sure there's other bad ways to create an equivalent to zipWith with a list comprehension, but I'm not terribly convinced that there's a good way, even from the ones above.

Cartesian product of infinite lists in Haskell

I have a function for finite lists
> kart :: [a] -> [b] -> [(a,b)]
> kart xs ys = [(x,y) | x <- xs, y <- ys]
but how to implement it for infinite lists? I have heard something about Cantor and set theory.
I also found a function like
> genFromPair (e1, e2) = [x*e1 + y*e2 | x <- [0..], y <- [0..]]
But I'm not sure if it helps, because Hugs only gives out pairs without ever stopping.
Thanks for help.
Your first definition, kart xs ys = [(x,y) | x <- xs, y <- ys], is equivalent to
kart xs ys = xs >>= (\x ->
ys >>= (\y -> [(x,y)]))
where
(x:xs) >>= g = g x ++ (xs >>= g)
(x:xs) ++ ys = x : (xs ++ ys)
are sequential operations. Redefine them as alternating operations,
(x:xs) >>/ g = g x +/ (xs >>/ g)
(x:xs) +/ ys = x : (ys +/ xs)
[] +/ ys = ys
and your definition should be good to go for infinite lists as well:
kart_i xs ys = xs >>/ (\x ->
ys >>/ (\y -> [(x,y)]))
testing,
Prelude> take 20 $ kart_i [1..] [101..]
[(1,101),(2,101),(1,102),(3,101),(1,103),(2,102),(1,104),(4,101),(1,105),(2,103)
,(1,106),(3,102),(1,107),(2,104),(1,108),(5,101),(1,109),(2,105),(1,110),(3,103)]
courtesy of "The Reasoned Schemer". (see also conda, condi, conde, condu).
another way, more explicit, is to create separate sub-streams and combine them:
kart_i2 xs ys = foldr g [] [map (x,) ys | x <- xs]
where
g a b = head a : head b : g (tail a) (tail b)
this actually produces exactly the same results. But now we have more control over how we combine the sub-streams. We can be more diagonal:
kart_i3 xs ys = g [] [map (x,) ys | x <- xs]
where -- works both for finite
g [] [] = [] -- and infinite lists
g a b = concatMap (take 1) a
++ g (filter (not . null) (take 1 b ++ map (drop 1) a))
(drop 1 b)
so that now we get
Prelude> take 20 $ kart_i3 [1..] [101..]
[(1,101),(2,101),(1,102),(3,101),(2,102),(1,103),(4,101),(3,102),(2,103),(1,104)
,(5,101),(4,102),(3,103),(2,104),(1,105),(6,101),(5,102),(4,103),(3,104),(2,105)]
With some searching on SO I've also found an answer by Norman Ramsey with seemingly yet another way to generate the sequence, splitting these sub-streams into four areas - top-left tip, top row, left column, and recursively the rest. His merge there is the same as our +/ here.
Your second definition,
genFromPair (e1, e2) = [x*e1 + y*e2 | x <- [0..], y <- [0..]]
is equivalent to just
genFromPair (e1, e2) = [0*e1 + y*e2 | y <- [0..]]
Because the list [0..] is infinite there's no chance for any other value of x to come into play. This is the problem that the above definitions all try to avoid.
Prelude> let kart = (\xs ys -> [(x,y) | ls <- map (\x -> map (\y -> (x,y)) ys) xs, (x,y) <- ls])
Prelude> :t kart
kart :: [t] -> [t1] -> [(t, t1)]
Prelude> take 10 $ kart [0..] [1..]
[(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(0,7),(0,8),(0,9),(0,10)]
Prelude> take 10 $ kart [0..] [5..10]
[(0,5),(0,6),(0,7),(0,8),(0,9),(0,10),(1,5),(1,6),(1,7),(1,8)]
you can think of the sequel as
0: (0, 0)
/ \
1: (1,0) (0,1)
/ \ / \
2: (2,0) (1, 1) (0,2)
...
Each level can be expressed by level n: [(n,0), (n-1, 1), (n-2, 2), ..., (0, n)]
Doing this to n <- [0..]
We have
cartesianProducts = [(n-m, m) | n<-[0..], m<-[0..n]]