'Flatten a nested list structure using concatMap gives error

Problem 7 from 99 Haskell problems

Flatten a nested list structure

This is my solution:

data NestedList a = Elem a | List [NestedList a]

myFlatten :: NestedList a -> [a]
myFlatten (Elem x) = [x]
myFlatten (List (x:xs)) = x : concatMap myFlatten xs

However, I would like to understand...Why does the compiler say:

Occurs check: cannot construct the infinite type: a ~ NestedList a

Expected type: [NestedList a] Actual type: [a]



Solution 1:[1]

Let's examine this part of the code, only:

myFlatten :: NestedList a -> [a]
myFlatten (List (x:xs)) = x : ...

Inside List we have x:xs, and by definition of List we find (x:xs) :: [NestedList a]. Hence:

x :: NestedList a
xs :: [NestedList a]

The returned value is x : ... and that is a list of the type of x, which is NestedList a. Hence, the return type is [NestedList a].

However, the signature of myFlatten says that the return type is [a]. This is possible only if [a] = [NestedList a], i.e. only if a = NestedList a, but that's impossible, hence the type error.

Solution 2:[2]

With List (x:xs), both x and xs are NestedList as, not as, you thus should use concatMap over the entire list, with:

myFlatten :: NestedList a -> [a]
myFlatten (Elem x) = [x]
myFlatten (List xs) = concatMap myFlatten xs

To avoid wrapping and unwrapping in singleton lists, you can work with a tail that you recursively pass to the list, with:

myFlatten :: NestedList a -> [a]
myFlatten = (`go` [])
    where go (Elem x) = (x :)
          go (List xs) = flip (foldr go) xs

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Willem Van Onsem