I have a question about the type definition for using foldl in Haskell, I have the types:
data Client = GovOrg String
| Company String Integer Person String
| Individual Person Bool
deriving Show
data Person = Person String String Gender
deriving Show
data Gender = Male | Female | Unknown
deriving (Show, Eq, Ord)
data GenderStat = GenderStat Gender Integer deriving Show
The foldl is defined using the following functions:
clientGender :: Client -> Gender
clientGender client = case client of
Company _ _ (Person _ _ gender) _ -> gender
Individual (Person _ _ gender) _ -> gender
_ -> Unknown
incrementGenderStat :: GenderStat -> GenderStat
incrementGenderStat (GenderStat gender num) = GenderStat gender (num + 1)
genderStats:: [GenderStat] -> Client -> [GenderStat]
genderStats [maleStat, femaleStat, unknownStat] client = case clientGender client of
Male -> [incrementGenderStat maleStat, femaleStat, unknownStat]
Female -> [maleStat, incrementGenderStat femaleStat, unknownStat]
Unknown -> [maleStat, femaleStat, incrementGenderStat unknownStat]
-- genderStatsOfClients :: Client a ->
genderStatsOfClients = foldl genderStats [GenderStat Male 0, GenderStat Female 0, GenderStat Unknown 0]
When I try and load my module into ghci
, it throws the error:
• Ambiguous type variable ‘t0’ arising from a use of ‘foldl’ │
prevents the constraint ‘(Foldable t0)’ from being solved. │
Relevant bindings include │
genderStatsOfClients :: t0 Client -> [GenderStat] │
(bound at src/Section2/DataTypes.hs:82:1) │
Probable fix: use a type annotation to specify what ‘t0’ should be. │
These potential instances exist: │
instance Foldable (Either a) -- Defined in ‘Data.Foldable’ │
instance Foldable Maybe -- Defined in ‘Data.Foldable’ │
instance Foldable ((,) a) -- Defined in ‘Data.Foldable’ │
...plus one other │
...plus 22 instances involving out-of-scope types │
(use -fprint-potential-instances to see them all) │
• In the expression: │
foldl │
genderStats │
[GenderStat Male 0, GenderStat Female 0, GenderStat Unknown 0] │
In an equation for ‘genderStatsOfClients’: │
genderStatsOfClients │
= foldl │
genderStats │
[GenderStat Male 0, GenderStat Female 0, GenderStat Unknown 0] │
Failed, modules loaded: none.
I have attempted to rectify this by providing a type annotation for the function as suggested:
-- genderStatsOfClients :: Foldable Client => ([GenderStat] -> a -> [GenderStat]) -> [GenderStat] -> [a] -> [GenderStat]
I want to know how can I provide an appropriate type constraint here, if I use Foldable Client a
, it says it was expecting one fewer argument to Foldable
.
I have also tried the type definition:
genderStatsOfClients :: (Foldable f, Client a) => ([GenderStat] -> (f a) -> [GenderStat]) -> [GenderStat] -> [(f a)] -> [GenderStat]
genderStatsOfClients = foldl genderStats [GenderStat Male 0, GenderStat Female 0, GenderStat Unknown 0]
which throws the error:
src/Section2/DataTypes.hs:81:38: error: │
• Expecting one fewer argument to ‘Client’ │
Expected kind ‘* -> Constraint’, but ‘Client’ has kind ‘*’ │
• In the type signature: │
genderStatsOfClients :: (Foldable f, Client a) => │
([GenderStat] -> (f a) -> [GenderStat]) │
-> [GenderStat] -> [(f a)] -> [GenderStat]
Annotate you definition of
genderStatsOfClients
to tell the compiler that your foldable is a list :