0

I'm trying to compile simple code snippet.

main = (putStrLn . show) (Right 3.423)

Compile results in the following error:

No instance for (Show a0) arising from a use of `show'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
  instance Show Double -- Defined in `GHC.Float'
  instance Show Float -- Defined in `GHC.Float'
  instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
    -- Defined in `GHC.Real'
  ...plus 42 others
In the second argument of `(.)', namely `show'
In the expression: putStrLn . show
In the expression: (putStrLn . show) (Right 3.423)

When i execute same snippet from ghci everything works as expected.

Prelude> let main = (putStrLn . show) (Right 3.423)
Prelude> main
Right 3.423

So the question is what is going on?

Alexander
  • 779
  • 8
  • 17

1 Answers1

6

The problem is that GHC can't determine what the full type of Right 3.423 is, it can only determine that it has the type Either a Double, and the instance of Show for Either looks like instance (Show a, Show b) => Show (Either a b). Without that extra constraint on Either a Double, GHC doesn't know how to print it.

The reason why it works in interactive mode is because of the dreaded monomorphism restriction, which makes GHCi more aggressive in the defaults it chooses. This can be disabled with :set -XNoMonomorphismRestriction, and that is going to become the default in future versions of GHC since it causes a lot of problems for beginners.

The solution to this problem is to put a type signature on Right 3.423 in your source code, like

main = (putStrLn . show) (Right 3.423 :: Either () Double)

Here I've just used () for a, since we don't care about it anyway and it's the "simplest" type that can be shown. You could put String or Int or Double or whatever you want there, so long as it implements Show.

A tip, putStrLn . show is exactly the definition of print, so you can just do

main = print (Right 3.423 :: Either () Double)


As @ØrjanJohansen points out, this is not the monomorphism restriction, but rather the ExtendedDefaultRules extension that GHCi uses, which essentially does exactly what I did above and shoves () into type variables to make things work in the interactive session.

Community
  • 1
  • 1
bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • 1
    Actually, `Data.Void.Void` is the simplest type in `Show`, although it can't actually be shown successfully. – dfeuer Jun 12 '14 at 14:02
  • 1
    @dfeuer Technically true, but `()` is a pretty simple choice to go with still. I figure it's an easier explanation that `()` can often be used to fill in type variables that don't really matter, but need to be concrete in order to satisfy a typeclass instance like `Show`. This obviously doesn't work for all situations, but it works pretty well for a lot of them. – bheklilr Jun 12 '14 at 14:06
  • 1
    This is not the monomorphism restriction, which is *always* on by default for file modules. It is because of GHCi's `ExtendedDefaultRules`, which allow it to choose a default (in fact the same `()` that you chose) even when only a `Show` instance is required (normally the restrictions include that at least one numerical class is needed.) – Ørjan Johansen Jun 12 '14 at 14:20
  • @ØrjanJohansen My mistake, I'll update my answer. I know I've seen the `ExtendedDefaultRules` before, but my first thought when I see a problem like this is the monomorphism restriction, and I probably just jumped the gun on answering the question instead of thinking about it for a few more minutes. – bheklilr Jun 12 '14 at 14:51
  • I don't think you need to strike out more than your second paragraph though, the rest is useful and applies to this case as well. – Ørjan Johansen Jun 12 '14 at 16:31