Reputation: 19195
I'm trying to write a function [a] -> Bool
which returns true when all elements of the list have the same lengths.
I tried to do this using list recursion and extracted the first two elements of the list with x : y : xs
then compared the length of x and y with length x == length y
as case determination. However, GHCi
complains about the types of x and y:
Couldn't match expected type `a' with actual type `[a0]'
`a' is a rigid type variable bound by
the type signature for [a] -> Bool
In the first argument of `length', namely `x'
In the first argument of `(==)', namely `length x'
In the expression: length x == length y
Why is this happening and how do I fix it? Clearly, length :: [a] -> Int == length :: [a] -> Int
returns a Bool
which is correct. In fact, replacing this expression by True
compiles.
Upvotes: 1
Views: 886
Reputation: 91897
The answers given so far don't work well when at least one list is list is finite and at least one is infinite: the function fails to terminate, when termination is possible, because they are busy calling length
on an infinite list. Below is an answer that works for any sort of list:
allSameLength :: [[a]] -> Bool
allSameLength [] = True
allSameLength xs = all null xs || all (not . null) xs && allSameLength (map tail xs)
It's a pretty easy recursive definition: either all the lists are empty, or none of them are empty and they're still the same length after you take out one element from each.
Upvotes: 0
Reputation: 13012
We can do this very simply, actually.
sameLengths :: [[a]] -> Bool
sameLengths [] = True
sameLengths (x:xs) = all (\y -> length y == length x) xs
No need for any recursion - all of the lengths are the same iff they are equal to the first one, so just extract the first and use all
to easily check the rest.
As for why you can't define for [a]
, remember that [String]
is a [[a]]
as well as an [a]
. But we specifically need [[a]]
because length
must be defined for whatever a
is in [a]
.
Upvotes: 5
Reputation: 120
There are two problems:
the length
function is defined on lists (length :: [a] -> Int
), so you
can not apply it to other types
you can certainly define a your own class:
class WithLength a where
myLength :: a -> Bool
but you must define an instance of this class for each possible type! For example:
instance WithLength Int where
myLength _ = 1
instance WithLength [a] where
myLength lst = length lst
Then, you can define you recursive function to check the same length properies.
Upvotes: 0