user4758246
user4758246

Reputation: 585

Problems writing my first Haskell Function

I'm new to Haskell and my code wont compile.

multipleSum :: Int -> Int
multipleSum x = let recSum 0 b = b
                    recSum a b | a mod 3 == 0     = recSum a-1 b+a
                               | a mod 5 == 0     = recSum a-1 b+a
                               | otherwise        = recSum a-1 b
                in recSum x 0 

These are the two errors I get, the first one occurs in line 3 and the second one in line 6. What am I doing wrong? (The function should be the sum of all multiples of 3 and 5 below n)

1.
Occurs check: cannot construct the infinite type: a ~ a -> a -> a
Expected type: (a -> a -> a) -> a -> a
  Actual type: ((a -> a -> a) -> a -> a) -> (a -> a -> a) -> a -> a
Relevant bindings include
  b :: (a -> a -> a) -> a -> a
    (bound at src\Main.hs:5:30)
  a :: (a -> a -> a) -> a -> a
    (bound at src\Main.hs:5:28)
  recSum :: ((a -> a -> a) -> a -> a)
            -> ((a -> a -> a) -> a -> a) -> (a -> a -> a) -> a -> a
    (bound at src\Main.hs:4:21)
In the first argument of `(-)', namely `recSum a'
In the first argument of `(+)', namely `recSum a - 1 b'


2.Couldn't match expected type `(a0 -> a0 -> a0) -> a0 -> a0'
            with actual type `Int'
In the first argument of `recSum', namely `x'
In the expression: recSum x 0

Couldn't match expected type `Int'
            with actual type `(a0 -> a0 -> a0) -> a0 -> a0'
Probable cause: `recSum' is applied to too few arguments
In the expression: recSum x 0
In the expression:
  let
    recSum 0 b = b
    recSum a b
      | a mod 3 == 0 = recSum a - 1 b + a
      | a mod 5 == 0 = recSum a - 1 b + a
      | otherwise = recSum a - 1 b
  in recSum x 0

Upvotes: 3

Views: 152

Answers (2)

Cirdec
Cirdec

Reputation: 24166

You have two problems related to syntax. The first has to do with function and operator precedence. Function application has the highest precedence in Haskell, so recSum a-1 b+a is treated as the same as (recSum a)-(1 b)+a. Instead you need to write recSum (a-1) (b+a).

The second problem is that a mod 3 is the function a called with the arguments mod and 3. To use mod as an infix operator, write it as

a `mod` 3

Putting both of these changes together we'd have

multipleSum :: Int -> Int
multipleSum x = let recSum 0 b = b
                    recSum a b | a `mod` 3 == 0  = recSum (a-1) (b+a)
                               | a `mod` 5 == 0  = recSum (a-1) (b+a)
                               | otherwise       = recSum (a-1) b
                in recSum x 0 

Upvotes: 8

AndrewC
AndrewC

Reputation: 32475

First thing is that the more type signatures you can get in, the easier it is to debug, so I'd rewrite it as

multipleSum :: Int -> Int
multipleSum x = recSum x 0

recSum :: Int -> Int -> Int
recSum 0 b = b
recSum a b | a mod 3 == 0     = recSum a-1 b+a
           | a mod 5 == 0     = recSum a-1 b+a
           | otherwise        = recSum a-1 b

and fire it up in ghci or hugs.

This way I get an error about a mod 3.

OK, well I have to write infix functions with backticks, so that should be

recSum :: Int -> Int -> Int
recSum 0 b = b
recSum a b | a `mod` 3 == 0     = recSum a-1 b+a
           | a `mod` 5 == 0     = recSum a-1 b+a
           | otherwise        = recSum a-1 b

Now I'm getting errors about the number of arguments in recSum a-1 b+a. That's because there should only be two, so I need brackets if I'm going to pass something more complicated than a single variable, so I should write

recSum :: Int -> Int -> Int
recSum 0 b = b
recSum a b | a `mod` 3 == 0     = recSum (a-1) (b+a)
           | a `mod` 5 == 0     = recSum (a-1) (b+a)
           | otherwise        = recSum (a-1) b -- don't need brackets for b on its own

Now it's compiled, it's time to test it out with various inputs to see if it does what it's supposed to.

Upvotes: 7

Related Questions