Reputation: 505
I started studying Haskell one week ago and have one strange problem. I created a simple data type and want to show it in a console. I created 2 functions for 2 constructors of my type. The compiler can call function if I use a constructor with 2 arguments. But it can't call another function which should catch a constructor with 1 argument.
module Main (
main
) where
data MyContainter a b = FirstVersion a b
| SecondVersion a
deriving(Show,Eq)
showContainer (FirstVersion a b) = show b
showContainer (SecondVersion a) = show a
--startF = showContainer (FirstVersion 1 2) -- it works
startF = showContainer (SecondVersion 1) -- it doesn't work
main = putStr startF
The compilers tells:
Ambiguous type variable `a0' in the constraint:
(Show a0) arising from a use of `showMaybe'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: showMaybe (SecondVersion 1)
In an equation for `startF': startF = showMaybe (SecondVersion 1)
Why does it tell that? I created (SecondVersion 1) directly and don't understand why the compiler doesn't call showContainer (SecondVersion a).
Upvotes: 7
Views: 242
Reputation: 40787
The problem is that showContainer
has the type:
showContainer :: (Show a, Show b) => MyContainer a b -> String
But when you pass SecondVersion 1
, it doesn't know what b
is, because SecondVersion 1
works for any type of b
! When you pass a FirstVersion
, it works fine, because, as FirstVersion
contains both an a
and a b
, there's never any ambiguity as to what they should be.
So, since the compiler has no way of knowing what b
you want, and no way of knowing that the choice of b
doesn't affect showContainer
(after all, it does affect the behaviour when you pass FirstVersion
, since it uses show
on a value of type b
), it gives up.
That's what the error message is saying: the type variable a0
1 is ambiguous, so please add a type signature to tell me what it is. In this case, it doesn't matter what it is, so you can just set it to ()
:
startF = showContainer (SecondVersion 1 :: MyContainer Integer ())
You probably won't run into errors like this very often, since the context you use the values in will usually force a specific b
to be used.
1 GHC isn't the best at picking type variables, unfortunately; if you gave showContainer
an explicit type signature like I showed, then it'd use b
in the error message too.
Upvotes: 9