Skip to content

"expected" and "got" are reversed with pattern signatures in do notation bind

With GHCi 8.4.?, these incorrect programs are given these errors:

*Frontend.CSS Obelisk.Run> let (x :: Int) = pure (1 :: Float) in ()

<interactive>:101:18: error:
     Couldn't match expected type Int with actual type f0 Float
     In the expression: pure (1 :: Float)
      In a pattern binding: (x :: Int) = pure (1 :: Float)
      In the expression: let (x :: Int) = pure (1 :: Float) in ()
*Frontend.CSS Obelisk.Run> (\(x :: Int) -> ()) (1 :: Float)

<interactive>:102:22: error:
     Couldn't match expected type Int with actual type Float
     In the first argument of \ (x :: Int) -> (), namely
        (1 :: Float)
      In the expression: (\ (x :: Int) -> ()) (1 :: Float)
      In an equation for it: it = (\ (x :: Int) -> ()) (1 :: Float)
*Frontend.CSS Obelisk.Run> do (x :: Int) <- pure (1 :: Float); pure ()

<interactive>:103:5: error:
     Couldn't match expected type Float with actual type Int
     When checking that the pattern signature: Int
        fits the type of its context: Float
      In the pattern: x :: Int
      In a stmt of a 'do' block: (x :: Int) <- pure (1 :: Float)

Notice how pattern signatures in let and lambda bindings are taken as authoritative: they give the "expected" type and the bound expression is blamed with its synthesized "actual" type. With do bindings, this is reversed, and the pattern signature is blamed instead when it doesn't match the synthesized "actual" type. This is at the very least inconsistent, and in my opinion the worse of the two options: I like to add signatures to "shift blame" and make the type checker look elsewhere, but if type signatures aren't taken as authoritative, this won't work.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information