Opened 10 months ago

Last modified 10 months ago

#15931 new bug

MonoLocalBinds + MonomorphismRestriction prevents generalization for a top level definition

Reported by: theindigamer Owned by:
Priority: low Milestone:
Component: Compiler Version: 8.6.2
Keywords: MonoLocalBinds, MonomorphismRestriction Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Incorrect error/warning at compile-time Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

Consider the following code sample

{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE MonomorphismRestriction #-}
tmp = 10
picker x y = if tmp > 11 then x else y
main = do
  print (picker "x" "y")
  print (picker 10 11)

It fails with the misleading error message "* No instance for (Num [Char]) arising from the literal `10'...", from what seems to be an interaction between MonoLocalBinds and MonomorphismRestriction (turn either off and the error goes away).

Should this be happening only for local bindings, or is it correct for this error to occur for top-level definitions too?

In either case, would it be possible to give a better error message here?

Change History (2)

comment:1 Changed 10 months ago by simonpj

Hmm. Here is what is happening.

  • tmp is not generalise because of the monomorphism restriction. So we get tmp :: alpha, for some as-yet-unknown type alpha; plus the constraint Num alpha.
  • MonoLocalBinds prevents generalisation of a binding if it mentions anything that has an open type; that is, a type with free type variables. tmp does, so picker is not generalised. So it gets type picker :: gamma -> gamma -> gamma.
  • Now we apply picker to both [Char] (from picker "x" "y") and delta (where we also need Num delta) from picker 10 11. So we say gamma := delta := [Char] and get stuck on Num [Char].

That's the diagnosis. The error message is unhelpful -- but it's not obvious to me how to improve it.

What error message would you like?

comment:2 Changed 10 months ago by theindigamer

Proposal 1 (somewhat radical)

In my experience, such error messages (the ones which are inaccurate, in contrast to most other messages) very often involve the MonomorphismRestriction in one way or another, as well as some function in the middle not having an explicit signature. Often the problem will go away once you add that missing signature.

So, if you get an error with MonomorphismRestriction on, and the error involves functions which do not have explicit signatures ("involves" would need to be more precisely defined...) - try turning it off and see if the error goes away. If it does, inform the user the "hey, MonomorphismRestriction is causing a problem, so please annotate foo with the type X" that I inferred with NoMonomorphismRestriction.

I don't know how practical this is or whether it could lead to undesirable consequences.

Proposal 2

In this particular case at least, a better error message would be with the substituted types -

Inferred picker :: [Char] -> [Char] -> [Char] due to

7 |     picker "x" "y"

and also picker :: Num a => a -> a -> a due to

8 |     picker 10 11
 
which conflict. Looks like picker doesn't have an explicit type
signature - try providing one to fix the issue, or get a more informative
error message.

Of course, the exact wording itself is not important, but now it is much clearer what the source of the problem is.

I'm not sure what the appropriate level of generality is here (to give this kind of error message).

Note: See TracTickets for help on using tickets.