Alexander
Alexander

Reputation: 779

Error while compiling print Either value

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?

Upvotes: 0

Views: 92

Answers (1)

bheklilr
bheklilr

Reputation: 54058

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.

Upvotes: 6

Related Questions