4
votes

I've been getting some strange typeclass errors of the form "No instance for (Test a0) arising from an expression type signature". Here is the simplest version of the offending code I could come up with:

class Test a where
  test :: a

foo = test

Adding the type doesn't help:

foo = test :: Test a => a

However, adding an instance of Test does make it compile:

instance Test Int where
  test = 0

This isn't really acceptable, as I want my instances declared elsewhere.

Finally, passing -XNoMonomorphismRestriction to ghc(i) also allows it to compile. While this is good enough for now, I don't understand what this extension does, why it is necessary, or what downsides may be lurking.

2

2 Answers

10
votes

As an alternative to disabling the monomorphism restriction for the whole file (which is fairly harmless, but can cause some unexpected recalculation of values that are not intended to be polymorphic), adding the type does help, but you have to do it as a signature at top level:

foo :: Test a => a
foo = test

If you add it just after test, it is considered just an annotation on the subexpression test, and does not turn off the monomorphism restriction for foo itself.

1
votes

After reading this article I finally understood the monomorphism restriction. The point is that things which look like constants shouldn't be polymorphic, as that might cause them to be evaluated multiple times (at worst resulting in exponential slowdowns).

In my actual case the "constant" was itself a function (via currying). I'm now on the fence; should I resort to -XNoMonomorphismRestriction, or add the type declaration? The latter seems less drastic/intrusive, but on the other hand I just don't like what the MR does to my types.