[Haskell-cafe] Help understanding type error

Stuart Cook scook0 at gmail.com
Fri Sep 7 00:20:40 EDT 2007


On 9/7/07, Levi Stephen <levi.stephen at optusnet.com.au> wrote:
> I'm after some help understanding either what I'm doing wrong, or why this error
> occurs.
>
> I have a data type:
>
>  > data T a = forall b. (Show b) => T b a

I should first point out that by mentioning b only on the RHS, you've
defined an existential type. If that's what you intended, then fine;
if not, the type you probably wanted was:

  data (Show b) => T b a = T b a

which makes most of these problems go away.


> and I want to use/extract 'b' from this.
>
>  > extShow (T b _) = b
>
> This gives the following compilation error:
>
> extest.hs:5:0:
>      Inferred type is less polymorphic than expected
>        Quantified type variable `b' escapes
>      When checking an existential match that binds
>         $dShow :: {Show b}
>         b :: b
>      The pattern(s) have type(s): T t
>      The body has type: b
>      In the definition of `extShow': extShow (T b _) = b

For reasons that I don't claim to completely understand, the compiler
doesn't allow "raw" existential types (such as the type of b) to
escape from their binding scope. See my final comment for a potential
workaround.


> I tried adding a type signature:
>
>  > extShow' :: (Show b) => T a -> b
>  > extShow' (T b _) = b

The type you've declared is:

  extShow' :: forall a b. (Show b) => T a -> b

which carries the implicit claim that for *any* instance of Show the
context desires, we can return a value of that type. This contradicts
the data type, which only contains a value of some *specific* type.

What you really want is something along the lines of:

  extShow' :: forall a. exists b. (Show b) => T a -> b  -- not valid Haskell!

which unfortunately isn't allowed.


> It seems (to newbie me ;) ) like it should be possible to extract the first part
> of T, and deduce that it is an instance of the class 'Show'.
>
> The following seems ok:
>
>  > doShow (T b _) = putStrLn (show b)

You can generalise this to arbitrary functions as follows:

  extShowWith :: (forall b. (Show b) => b -> c) -> T a -> c
  extShowWith f (T b _) = f b

  doShow = extShowWith (putStrLn . show)

This works because f is required to accept *any* Show instance as an
argument type, and so is happy to work for whatever particular type b
happens to inhabit.


Stuart Cook


More information about the Haskell-Cafe mailing list