Craig Traynor
Craig Traynor

Reputation: 449

Sum function in haskell producing 'Non-exhaustive pattern' error

Here is an example of my code that is producing the error:

amount :: [Int, Int, Int] -> Int
amount [(a, b, c)] = sum( map getBalance [(a, b, c)])
                         where getBalance :: (Int,Int,Int) -> Int
                               getBalance (d, e, f) = f
amount [] = 0

Originally the code was just:

amount :: [Int, Int, Int] -> Int
amount [(a, b, c)] = sum [c]

But I tried rewriting and adding things to see if I could find the cause of the error, and I couldn't. I'm rather new to Haskell, so if it's a stupid error I apoligise.

Upvotes: 1

Views: 828

Answers (4)

Landei
Landei

Reputation: 54584

I certainly wouldn't recommend to make Int a Monoid in "serious" code, but it would work:

import qualified Data.Foldable as F
import Data.Monoid

amount :: [(Int,Int,Int)] -> Int
amount xs = let (_,_,x) = F.fold xs in x 

instance Monoid Int where
  mempty = 0
  mappend = (+)

Upvotes: 0

Yann Vernier
Yann Vernier

Reputation: 15877

The type signature you've written describes a list of three Ints: [Int, Int, Int]. The list types have indeterminate length, however, and the amount function you've written seems to expect 3-tuples of Ints, which would be written as [(Int, Int, Int)]; this can be derived from the definition anyway. Loading the first code block into ghci therefore produced:

test.hs:1:11:
    Illegal type: '[Int, Int, Int]

The second error appears once I provide it with a longer list of input:

*Main> amount [(1,2,3),(4,5,6)]
*** Exception: test.hs:(2,1)-(5,13): Non-exhaustive patterns in function amount

The problem here is that neither of the patterns match: you have patterns for lists with one or zero entries, but not more. Seeing that [(a, b, c)] is a repeated expression, how about we just replace it?

amount [] = 0
amount xs = sum( map getBalance xs)
                     where getBalance :: (Int,Int,Int) -> Int
                           getBalance (d, e, f) = f

Now any length of list will be passed to map, which is fine, because it is meant to handle an arbitrary length. So is sum, actually, so we didn't even need to add the special case for an empty list.

If you want to add a pattern for the longer-than-one lists, the traditional form is x:xs, breaking it up into a head x and tail xs. That pattern doesn't match the empty list, because it cannot be split.

The problem with your original code was also that it only defined a version for a list of one tuple. We can use list comprehension or map to handle that:

amount1 abcs = sum [c | (a,b,c) <- abcs]
amount2 = sum . map (\(a,b,c) -> c)

All of these variants do the same thing, even though amount2 didn't even mention an argument.

Upvotes: 4

kaan
kaan

Reputation: 796

First, your type signature is wrong, it has to be

amount :: [(Int, Int, Int)] -> Int

The "Non-Exhaustive pattern Error occurs, because you provided only two cases of lists: At the bottom the case for empty list [], and above the case, where the list holds one element ([(a,b,c)] is a list with the element (a,b,c). Hence your code would work with amount [(1,2,3)])

Easiest way: Replace [(a,b,c)] with xs, at the left of the = and the right.

Upvotes: 1

wit
wit

Reputation: 1622

(a,b,c) is a tuple: (a,b,c) = (,,) a b c

amount :: [(Int, Int, Int)] -> Int
amount [(a, b, c)] = ...

The right one

Upvotes: 0

Related Questions