5
votes

So I'm new to Haskell and I'm writing a basic function which takes 3 integers as arguments and returns how many are equal.

howManyEqual :: Int->Int->Int->Integer

howManyEqual x y z =  
        if x == y && x == z then return 3
        else if x == y && x /= z then return 2
        else if x == z && x /= y then return 2
        else if y == z && y /= x then return 2
        else return 0

But Im getting the following error:

Prelude> :load ex4.1_2.hs 
[1 of 1] Compiling Main             ( ex4.1_2.hs, interpreted )

ex4.1_2.hs:11:34:
    Couldn't match expected type ‘Integer’
                with actual type ‘m0 Integer’
    In the expression: return 3
    In the expression:
      if x == y && x == z then
          return 3
      else
          if x == y && x /= z then
              return 2
          else
              if x == z && x /= y then
                  return 2
              else
                  if y == z && y /= x then return 2 else return 0

I have same error at return 2 and return 0 as well. What kind of data type is m0 Integer and what do I need to do to fix this? Any help would be appreciated. Cheers!!

2
All of your /= checks could be removed. You already know, because the first check failed, that the three numbers are not all equal. Therefore, if (for example) x == y, then you already know that x /= z and do not need to test it.amalloy
You could also use something more compact by counting equalities regardless of order: howManyEqual x y z | and xyz = 3 | or xyz = 2 | otherwise = 0 where xyz = [x == y, x == z, y == z]—that is, if all of them compare equal, then 3 are equal; if only some of them compare equal, then 2 are equal; otherwise 0 are equal.Jon Purdy

2 Answers

8
votes

Delete all the return keywords:

howManyEqual :: Int -> Int -> Int -> Integer
howManyEqual x y z =  
  if x == y && x == z then 3
  else if x == y && x /= z then 2
  else if x == z && x /= y then 2
  else if y == z && y /= x then 2
  else 0

In Haskell, return isn't a keyword, but a function with the type Monad m => a -> m a. It's mainly used from within code blocks in do notation to return values 'wrapped' in a Monad instance.

The howManyEqual method doesn't return a monadic value, but rather a normal, scalar Integer, so return isn't required. When you use return anyway, the compiler expects the returned value to be part of some Monad instance that it calls m0 in the error message, but since the function has the explicitly declared return type Integer, there's no way to reconcile these.

By the way, you can relax the type declaration to:

howManyEqual :: (Eq a, Num t) => a -> a -> a -> t
5
votes

Some further off topic information about the haskell syntax:

There is nothing wrong with using else if in haskell, but it's not common. Haskell supports guards | which is some what equivalent to else if. However, if x then y else z is mosty used for a binary condition, not to gather several different conditions.

| x == y = 5 = if x ==y then 5

Therefore your code could be expressed in the following and more preferable way

 howManyEqual :: Int -> Int -> Int -> Integer
 howManyEqual x y z   
   | x == y && x == z = 3
   | x == y && x /= z = 2
   | x == z && x /= y = 2
   | y == z && y /= x = 2
   | otherwise        = 0