Opened 10 years ago

Closed 9 years ago

#3613 closed bug (fixed)

Better error messages for do-notation

Reported by: simonpj Owned by:
Priority: normal Milestone: 7.0.1
Component: Compiler (Type checker) Version: 6.10.4
Keywords: Cc: red5_2@…, michal.terepeta@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect warning at compile-time Test Case: typecheck/should_fail/T3613
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

C Rodrigues [red5_2@…] writes: In this example, fun1 and fun2 are basically the same. The type error is because they try to run an IO () together with a Maybe ().

> import Control.Monad
>
> foo :: Maybe ()
> foo = return ()
>
> bar :: IO ()
> bar = return ()
>
> fun1 = let fooThen m = foo>> m
>        in fooThen (bar>> undefined)
>
> fun2 = let fooThen m = foo>> m
>        in fooThen (do {bar; undefined})

With ghc 6.10.4, both functions attribute the error message to `bar'. However, the expected and inferred monads are swapped.

  • fun1 produces the error message:
    Couldn't match expected type `Maybe a' against inferred type `IO ()'
    In the first argument of `(>>=)', namely `bar'
    
  • fun2 produces the error message:
    Couldn't match expected type `IO ()' against inferred type `Maybe ()'
    In a stmt of a 'do' expression: bar
    

It's confusing because 'bar' is inferred to have type Maybe (), even though it's explicitly declared to be an IO ().

Change History (5)

comment:1 Changed 10 years ago by simonpj

I agree this is confusing. I had a look at the code. When typechecking x <- rhs, GHC does this (TcMatches.tcDoStmt)

  • First infers the type of rhs
  • Then feed that into a typecheck of the bind operator >>=

Instead, the programmer expects the reverse, so that information about which monad is involved gets fed into the argument.

I don't expect anyone else to understand this note; it's an aide-memoire for me to remind me to fix this.

Simon

comment:2 Changed 10 years ago by simonpj

Milestone: 6.14 branch

I've improved matters as a side consequence of

Wed Oct 28 06:35:54 PDT 2009  simonpj@microsoft.com
  * Add 'rec' to stmts in a 'do', and deprecate 'mdo'
  
  The change is this (see Trac #2798).  
   ...

However the interaction of GADTs and impredicative polymorphism defeated me, so I only dealt with (>>) and not (>>=).

When the long-heralded re-engineering of type inference for GADTs takes place, I'll come back to this.

Simon

comment:3 Changed 10 years ago by igloo

Milestone: 6.14 branch6.14.1

comment:4 Changed 9 years ago by michalt

Cc: michal.terepeta@… added
Type of failure: Incorrect warning at compile-time

This seems to work fine with HEAD (i.e. even with (>>=)). So adding the following to the original examples:

> fun1' = let fooThen m = foo>> m
>         in fooThen (bar>>= \x -> undefined)
>
> fun2' = let fooThen m = foo>> m
>         in fooThen (do {x <- bar; undefined})

I get:

  • for fun1:
        Couldn't match expected type `Maybe a' with actual type `IO ()'
        In the first argument of `(>>)', namely `bar'
    
  • for fun2:
        Couldn't match expected type `Maybe a' with actual type `IO ()'
        In a stmt of a 'do' expression: bar
    
  • for fun1':
        Couldn't match expected type `Maybe a' with actual type `IO ()'
        In the first argument of `(>>=)', namely `bar'
    
  • and finally for fun2':
        Couldn't match expected type `Maybe a' with actual type `IO ()'
        In a stmt of a 'do' expression: x <- bar
    

Which seems ok to me. So unless I'm missing something the ticket can be closed as fixed..?

Just for the record:

> ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.1.20101008

comment:5 Changed 9 years ago by simonpj

Resolution: fixed
Status: newclosed
Test Case: typecheck/should_fail/T3613

Ah yes, it does seemt to be fixed. Moreover, we already have a regression test to check it stays fixed (I've added it to the ticket description, but it was already in the testsuite). So yes let's close it.

Thanks for pointing this out; very helpful.

Simon

Note: See TracTickets for help on using tickets.