Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Type error with where

Tags:

types

haskell

type NI = Int
type Age = Int
type Balance = Int
type Person = (NI, Age, Balance) 
type Bank = [Person]


sumAllAccounts :: NI -> Bank -> Int
sumAllAccounts n l = filter niMatch l
    where niMatch n (a,_,_) 
        | n == a    =   True
        | otherwise =   False

When I run this function i get a type error

couldnt match type (Person, t0, t1) -> Bool with Bool

However when I make the where its own function it works

personNIMatchs :: NI -> Person -> Bool
personNIMatchs n (a,_,_) 
    | n == a    =   True
    | otherwise =   False
like image 675
user972183 Avatar asked Oct 07 '13 05:10

user972183


1 Answers

Let's look at the type of filter

filter :: (a -> Bool) -> [a]-> [a]

The type of niMatch is NI -> Person -> Bool

So Haskell unifies a with NI, but Person -> Bool doesn't work! That's not a Bool, hence your somewhat confusing error message. To see this visually Haskell is unifying

   a   -> Bool
-- ^      ^ unification error!
   NI  -> (Person -> Bool) 

Now I assume that type Bank = [Person] then you just want

 sumAllAccounts n = sum . map getBalance . filter matchNI
   where matchNI (a, _, _) = a == n
         getBalance (_, _, b) = b
 -- I've added the code here to actually sum the balances here
 -- without it, you're returning a Bank of all a persons accounts.

But we can make this better! Let's do the more idiomatic Haskell approach and store Person as a record.

newtype Person = Person {
  ni :: NI,
  age :: Age,
  balance :: Balance
} deriving (Eq, Show)

sumAllAccounts :: NI -> Bank -> Balance
sumAllAccounts n = sum . map balance . filter ((==n) . ni)

Much neater, now we can use the autogenerated getters.

like image 141
Daniel Gratzer Avatar answered Nov 09 '22 20:11

Daniel Gratzer