Garry Cairns
Garry Cairns

Reputation: 3115

Pattern matching Haskell lists

I'm starting to learn Haskell using the University of Pennsylvania's free online course materials. These have been put online deliberately so I presume I'm not helping anyone's homework by asking this question.

I get a number of compiler errors from the following function, which I'm using to answer part of the first assignment, and I can't figure out why. My function is:

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther [x] = [x]
doubleEveryOther [x:y] = [x:(y*2)]
doubleEveryOther [x:y:ys] = [x:y*2:doubleEveryOther ys]

The errors I get are:

01.hs:18:19:
    Couldn't match expected type ‘Integer’ with actual type ‘[a0]’
    In the pattern: x : y
    In the pattern: [x : y]
    In an equation for ‘doubleEveryOther’:
        doubleEveryOther [x : y] = [x : (y * 2)]

01.hs:18:27:
    Couldn't match expected type ‘Integer’ with actual type ‘[a0]’
    Relevant bindings include
      y :: [a0] (bound at 01.hs:18:21)
      x :: a0 (bound at 01.hs:18:19)
    In the expression: x : (y * 2)
    In the expression: [x : (y * 2)]
    In an equation for ‘doubleEveryOther’:
        doubleEveryOther [x : y] = [x : (y * 2)]

01.hs:19:19:
    Couldn't match expected type ‘Integer’ with actual type ‘[Integer]’
    In the pattern: x : y : ys
    In the pattern: [x : y : ys]
    In an equation for ‘doubleEveryOther’:
        doubleEveryOther [x : y : ys] = [x : y * 2 : doubleEveryOther ys]

01.hs:19:30:
    Couldn't match expected type ‘Integer’ with actual type ‘[Integer]’
    In the expression: x : y * 2 : doubleEveryOther ys
    In the expression: [x : y * 2 : doubleEveryOther ys]
    In an equation for ‘doubleEveryOther’:
        doubleEveryOther [x : y : ys] = [x : y * 2 : doubleEveryOther ys]

Can anyone help me understand why my patterns are not matching the right types?

Upvotes: 2

Views: 1700

Answers (3)

viorior
viorior

Reputation: 1803

In addition, your 3rd line is a part of 4th line, so

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther [x]= [x]
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys

Upvotes: 1

nponeccop
nponeccop

Reputation: 13677

The problem is simple: [] denotes a list of elements. And : denotes joining an element and a list. So [x:ys] means actually [[x,y1,y2..]] - note double brackets. So it's a list of lists of Integer in your case and not a list of Integer.

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther [x]= [x]
doubleEveryOther [x,y] = [x, y*2]
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys

If you want all 4 equations to use the same syntax, then you can't use [] as it doesn't allow ys, so you have to use : everywhere:

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther (x:[])= x:[]
doubleEveryOther (x:y:[]) = x : y*2 : []
doubleEveryOther (x:y:ys) = x : y*2 : doubleEveryOther ys

Upvotes: 3

Ramith Jayatilleka
Ramith Jayatilleka

Reputation: 2152

The code should be:

doubleEveryOther :: [Integer] -> [Integer]
doubleEveryOther [] = []
doubleEveryOther [x] = [x]
doubleEveryOther (x:y:[]) = [x, (y*2)]
doubleEveryOther (x:y:ys) = x: y*2 : doubleEveryOther ys

You can't pattern match on a list directly, because the list syntax is just syntax sugar. You have to match on function calls (specifically calls to (:), the cons operator). And those matches need to be enclosed in parentheses.

And you don't enclose cons calls in brackets. [1 : 2 : []] is the same as [[1, 2]]. Just to make it a bit clearer, in your code you have [x : y*2]. x and y are both Ints. But cons (:) is of type (:) :: a -> [a] -> [a]. You're calling it with two Ints, not an Int and a [Int] like you should.

Upvotes: 2

Related Questions