1

I'm trying to set up a series of tests for a simple tic tac toe program I've written in Haskell and I'm unable to get past my first test due to a strange error being thrown reading:

Tests.hs:11:61: error:
    * Couldn't match expected type `Int' with actual type `IO Int'
    * In the third argument of `assertEqual', namely
        `(test_user_value x)'
      In the first argument of `TestCase', namely
        `(assertEqual "for (test_user_value 3)," f (test_user_value x))'
      In the expression:
        TestCase
          (assertEqual "for (test_user_value 3)," f (test_user_value x))
   |
11 | test1 = TestCase (assertEqual "for (test_user_value 3)," f (test_user_value x))
   |                                                             ^^^^^^^^^^^^^^^^^
Failed, one module loaded.

The value 'x' is an int but Haskell is reading it as 'IO Int' which is wrong, as I've specified "x :: Int". The function being tested has already been specified as "test_user_value :: Int -> IO Int" so I'm unsure why it is interpreting the variable incorrectly. Any suggestions would be appreciated.

  • 2
    Good question. Just listening to your use of language ... when working with Haskell, you must humble yourself. Unless you are doing something very fancy indeed, when the compiler gives you an error, the compiler is right, and you are wrong. ;) Your job is to determine in what way you have erred (which the error messages may or may not be of help with, depending on the circumstance). It's very different than, say, C++ where you just have to know the right magic spell to get the compiler to accept your code the way you wrote it. – luqui May 13 '20 at 00:05

1 Answers1

2

It's not actually complaining about x, it's complaining about the expression test_user_value x - note that it is this expression that is underlined in the error message.

Since, as you have indicated, test_user_value :: Int -> IO Int and x :: Int, it follows that test_user_value x :: IO Int - and that's exactly what the compiler tells you shouldn't be there. It's expecting an Int, but you gave it IO Int.

You can get an Int out of it though. To do that, I think the do notation would be the clearest:

test1 = TestCase $ do
    v <- test_user_value x
    assertEqual "for (test_user_value 3)," f v

Or you could write it a bit shorter using the =<< operator:

test1 = TestCase (assertEqual "for (test_user_value 3)," f =<< test_user_value x)
Fyodor Soikin
  • 78,590
  • 9
  • 125
  • 172