"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.