Using foldl in a function

182 views Asked by At

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]
1

There are 1 answers

1
Jean-Baptiste Potonnier On BEST ANSWER

Annotate you definition of genderStatsOfClientsto tell the compiler that your foldable is a list :

genderStatsOfClients :: [Client] -> [GenderStat]