Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functions for different data constructors

Tags:

haskell

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).

like image 654
Alexey Avatar asked Feb 04 '12 17:02

Alexey


1 Answers

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 a01 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.

like image 88
ehird Avatar answered Oct 03 '22 21:10

ehird