3

I have been trying a little example from the answer to this question:

liftTup :: (x -> f x) -> (a, b) -> (f a, f b)
liftTup liftFunc (t, v) = (liftFunc t, liftFunc v)

This clearly needs forall quantifier to work, but I am trying to understand the error message syntax to be able to know what's wrong if I get similar ones in future. So for this one I get:

monad.hs:112:28-37: Couldn't match type `x' with `b' …
      `x' is a rigid type variable bound by
          the type signature for
            liftTup :: (x -> f x) -> (a, b) -> (f a, f b)
          at /Users/user/monad.hs:111:12
      `b' is a rigid type variable bound by
          the type signature for
            liftTup :: (x -> f x) -> (a, b) -> (f a, f b)
          at /Users/user/monad.hs:111:12
    Expected type: f a
      Actual type: f x
    In the return type of a call of `liftFunc'
    In the expression: liftFunc t
    In the expression: (liftFunc t, liftFunc v)
monad.hs:112:40-49: Couldn't match type `a' with `b' …
      `a' is a rigid type variable bound by
          the type signature for
            liftTup :: (x -> f x) -> (a, b) -> (f a, f b)
          at /Users/user/monad.hs:111:12
      `b' is a rigid type variable bound by
          the type signature for
            liftTup :: (x -> f x) -> (a, b) -> (f a, f b)
          at /Users/user/monad.hs:111:12
    Expected type: f b
      Actual type: f x
    In the return type of a call of `liftFunc'
    In the expression: liftFunc v
    In the expression: (liftFunc t, liftFunc v)

So as far as I can tell the first error is related to applying liftFunc to t for the first time, so it tries to match f x with f a. But how is b related to this at all? b only appears in the second element of the tuple.

The second error I guess comes from the fact that a was matched to x in the previous liftFunc application, and now we are trying to match it to b in the second one, but that doesn't quite work. Is this right?

What's the correct way to read these error messages and what's the relation between variables mentioned in "Couldn't match type .. with .." and variables mentioned in "Expected type: .. Actual type: .. " messages?

Community
  • 1
  • 1
egdmitry
  • 2,071
  • 15
  • 18
  • My guess (which is uneducated enough that I won't make it an answer), is that GHC *first* tries to unify type variables to make everything well typed, at which point it finds that all of `a`, `b` and `x` must be the same; and only *then* checks whether any of the three variables are rigid and cannot be unified with each other, giving this random-looking pairing of culprits. – Ørjan Johansen Jun 02 '14 at 02:41

2 Answers2

4

You're reading the type errors correctly:

  1. GHC is trying to infer/check the type of the expression liftFunc t
  2. It discovered that the return type of this application of liftFunc would be f x
  3. It discovered that the expected type of this expression should be f a
  4. This requires that f x and f a are the same type; the point GHC broke down in trying to prove that was in requiring that x and b were the same thing

The "expected type" and "actual type" relate to the type of the expression it talks about immediately after ("In the return type of a call to liftFunc ..."). But "Couldn't match type 'x' with 'b'" is telling you about the thing it has noticed is impossible, when trying to match up the expected type with the actual type, so it's not necessarily going to report directly that that the two don't match.

This is perhaps unintuitive, but it's valid. Because liftFunc has a monomorphic type within liftTup, and it is applied to values of both types a and b, the type checker infers that x, a, and b must all be equal. So x ~ b (~ is how type equality is written in Haskell) really is something that must hold for this to be a well-typed expression, and establishing that it can't be unified (by observing that x and b are both "rigid type variables" that have to stay independently universally quantified) does establish that there is a type error.

My guess would be that the type checker has done some analysis to come up with a set of pairwise constraints including f x ~ f a, f x ~ f b, x ~ a, x ~ b, and a ~ b, and then started to prove them. Perhaps x ~ b was the simply the first one it tried. Or perhaps it had to prove x ~ a, and with no direct way to prove that and the only other information available being a ~ b it tried applying that to derive x ~ b, and then with no way to prove that (and a loop check stopping it from applying b ~ a to end up back at x ~ a again) it fails at that point. Something along those lines anyway. I'm pretty x ~ b was simply the first thing it happened to notice was impossible in the process of trying to check liftFunc t.

Ben
  • 68,572
  • 20
  • 126
  • 174
2

These errors are quite descriptive of your problem. But reading ghc error messages is sometimes difficult since they contain so much information.

Couldn't match type x with b means that it expects that x and b be the same type, but it can't prove that. Likewise for the other error. So from the two errors together, you know that the compiler expects a==b==x but that is not what you've written.

But you don't know why it actually does expect this, yet. The first error message says the following:

Expected type: f a
  Actual type: f x
In the return type of a call of `liftFunc'

You claim that the type of liftunc is x -> f x. But then you also claim that liftFunc t has type f a. From this, the only thing that the compiler can deduce that a and x must be same type. But there is no way to prove that, hence, type error.

The second error is applying the exact same logic to the second argument of the tuple.

user2407038
  • 14,400
  • 3
  • 29
  • 42