compsciman
compsciman

Reputation: 379

Haskell - Why can't I map into a sorted and grouped list of lists?

I have a function:

listLengths :: [Int] -> [Int]
listLengths xs = map length sort(group(xs))

The sort and group work so when I input say [1,3,5,5,3] it separates and sorts it into [[1],[3,3],[5,5]]. However when I add map length as above it should then say [1,2,2] (the lengths of each of those lists but all I seem to get are type errors.

Upvotes: 1

Views: 841

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477160

Because in Haskell function calls are done like f x, not f (x). Sure in many cases f (x) will work as well, but here you have basically written:

listLengths xs = map length sort (group(xs))

or more verbose:

listLengths xs = ((map length) sort) (group(xs))

Haskell thus sees sort as an independent parameter, and group (xs) as an extra one. But since sort is a function, and not a list, the typechecker will raise an error.

You can write it like:

listLengths :: [Int] -> [Int]
listLengths xs = map length (sort (group xs))

We here thus use brackets to specify that sort (group xs) is a parameter, the parameter in a function application with the function map length :: [[a]] -> [Int].

Alternatively, we can use a point-free way like:

listLengths :: [Int] -> [Int]
listLengths = map length . sort . group

Here we make use of the (.) :: (b -> c) -> (a -> b) -> a -> c function to "chain" functions together. Notice that we do not have an xs parameter here. We thus construct a new function that first applies group to the input, then the output of this function is passed to the sort function, and finally the output of this function application is passed to the map length function.

This will produce the output:

Prelude Data.List> listLengths xs = map length (sort (group xs))
Prelude Data.List> listLengths [1,3,5,5,3]
[1,1,1,2]

which is not completely what you want. This is because now we construct as groups: [[1], [3], [5,5], [3]] and then we sort these like [[1], [3], [3], [5, 5]] and then it will result in [1, 1, 1, 2] when we calculate the length of each subelement.

What you thus probably want is:

listLengths :: [Int] -> [Int]
listLengths = map length . group . sort

Upvotes: 2

Related Questions