Reputation: 1155
I'm trying to create a function that packs equal elements to a list. This is a training problem so I want to make my own sollution to work. I'm not looking for alternative ways to solve the problem, I would just like to understand why this code does not compile.
Here's the function:
pack :: Eq a => [a] -> [[a]]
pack xs = let packHelper acc [] = acc
packHelper acc zs = let splitOff = takeWhile (\y -> y == (head zs)) zs
in packHelper ( (splitOff:acc) (drop (length splitOff) zs) )
in packHelper [[]] xs
And the test case:
pack ['a', 'a', 'a', 'a', 'b', 'c', 'c', 'a', 'a', 'd', 'e', 'e', 'e', 'e']
==
["aaaa","b","cc","aa","d","eeee"]
The current implementation does not compile and gives this error:
main.hs:109:15: error:
* Couldn't match type `[a1] -> [[a1]]' with `[[a1]]'
Expected type: [[a1]] -> [[a1]]
Actual type: [[a1]] -> [a1] -> [[a1]]
* In the expression:
let
packHelper acc [] = acc
packHelper acc zs
= let ...
in packHelper ((splitOff : acc) (drop (length splitOff) zs))
in packHelper [[]] xs
In an equation for `pack':
pack xs
= let
packHelper acc [] = acc
packHelper acc zs = ...
in packHelper [[]] xs
* Relevant bindings include
packHelper :: [[a1]] -> [[a1]]
(bound at main.hs:109:15)
|
109 | pack xs = let packHelper acc [] = acc
| ^^^^^^^^^^^^^^^^^^^^^^^^...
main.hs:111:52: error:
* Couldn't match expected type `[a1] -> [[a1]]'
with actual type `[[a1]]'
* The function `splitOff : acc' is applied to one argument,
but its type `[[a1]]' has none
In the first argument of `packHelper', namely
`((splitOff : acc) (drop (length splitOff) zs))'
In the expression:
packHelper ((splitOff : acc) (drop (length splitOff) zs))
* Relevant bindings include
splitOff :: [a1]
(bound at main.hs:110:39)
zs :: [a1]
(bound at main.hs:110:30)
acc :: [[a1]]
(bound at main.hs:110:26)
packHelper :: [[a1]] -> [[a1]]
(bound at main.hs:109:15)
|
111 | in packHelper ( (splitOff:acc)
(drop (length splitOff) zs) )
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
main.hs:112:15: error:
* Couldn't match expected type `[a] -> [[a]]'
with actual type `[[a0]]'
* The function `packHelper' is applied to two arguments,
but its type `[[a0]] -> [[a0]]' has only one
In the expression: packHelper [[]] xs
In the expression:
let
packHelper acc [] = acc
packHelper acc zs
= let ...
in packHelper ((splitOff : acc) (drop (length splitOff) zs))
in packHelper [[]] xs
* Relevant bindings include
xs :: [a]
(bound at main.hs:109:6)
pack :: [a] -> [[a]]
(bound at main.hs:109:1)
|
112 | in packHelper [[]] xs
| ^^^^^^^^^^^^^^^^^^
Why does the compiler expect [[a1]] -> [[a1]] and not [[a1]] -> [a1] -> [[a1]] for packHelper?
Upvotes: 1
Views: 48
Reputation: 12123
The problematic part is:
in packHelper ( (splitOff:acc) (drop (length splitOff) zs) )
Note: you have parentheses around both supposed packHelper
arguments.
Fix is easy:
in packHelper (splitOff:acc) (drop (length splitOff) zs)
Then packHelper
is applied to two arguments and type-checking works out.
The type-error you see is caused by GHC trying to unify
-- infered from last `in`
-- - [[]] is `[[a1]`` "some" list-of-lists
-- - [a] is the type of xs
-- - [[a]] is the result type of `pack`
packHelper :: [[a]] -> ([a] -> [[a]])
with
-- because in inner `in` packHelper is applied to one argument only,
-- but result should be [[a]], the result type of `pack`
-- first argument can be "something" so far.
packHelper :: b -> [[a]]
So GHC get's missmatch between [a] -> [[a]]
and [[a]]
which it reports.
In general such errors "a -> b
doesn't match b
" are usually a sign that you forgot to apply an argument.
Upvotes: 2