4

I've reduced everything down to the essentials, so bear with me if the example code below is contrived. Let's say we have:

class Foo a where
    foo :: a

data Type a = Type a

instance (Foo a) => Foo (Type a) where
    foo = Type foo

Now, suppose I want to make Type a an instance of, say, Show whenever a is an instance of both Foo and Show (Show was chosen to avoid defining another typeclass). So how do we want Type a to be an instance of Show? Well, unless we're crazy, we'd of course want it to be something like

instance (Foo a, Show a) => Show (Type a) where
    show (Type x) = show x

or maybe

instance (Foo a, Show a) => Show (Type a) where
    show (Type x) = "Blabla " ++ (show x)

That's all great and works fine. For some inexplicable reason, we'd like show to output whatever foo :: a looks/shows like! In our contrived setting I cannot imagine why we'd want that, but let's say we do. Shouldn't

instance (Foo a, Show a) => Show (Type a) where
    show _ = show foo

do the trick?

Alas, GHC says

Ambiguous type variable 'a' in the constraints: 'Foo a' [...] 'Show a'

Maybe GHC can't figure out which foo I'm talking about. Do I mean foo :: Type a or foo :: a? Changing the previous snippet to

instance (Foo a, Show a) => Show (Type a) where
    show _ = show (foo :: a)

gives me

Could not deduce (Foo a1) from the context () arising from a use of 'foo' at [...] Possible fix: add (Foo a1) to the context of an expression type signature In the first argument of 'show', namely '(foo :: a)' In the expression: show (foo :: a)

At this point I'm starting to think I've misunderstood something basic. Yet, I have the strange feeling that similar constructions have worked for me in the past.

1 Answer 1

6

I think the problem is that type variables aren't scoped to definitions. That is, in

instance (Foo a, Show a) => Show (Type a) where
    show _ = show (foo :: a)

a in the second line is different from a in the first line, which is why it's shown as a1 in the error message. See http://www.haskell.org/haskellwiki/Scoped_type_variables. If this is the problem, this should work (I don't have GHC on this machine):

asTypeOf :: a -> a -> a
asTypeOf a b = a

instance (Foo a, Show a) => Show (Type a) where
    show (Type x) = show (foo `asTypeOf` x)
Sign up to request clarification or add additional context in comments.

5 Comments

Good answer except for a minor typo which leads to non-termination: the last line should be show (Type x) = show (foo `asTypeOf` x). You can also use {-# LANGUAGE ScopedTypeVariables #-} along with show _ = show (foo :: a)
Great! Thanks, this really clarified things. Thanks also to pelotom for pointing out the GHC extension.
The reason why I didn't mention the extension is that it requires that forall be written explicitly: haskell.org/ghc/docs/6.12.2/html/users_guide/…, but I wasn't sure where it should go: instance forall a. (Foo a, Show a) => Show (Type a)? Somewhere else? Unnecessary for instances?
Alexey: I didn't need forall at least. In my example, I turned on the GHC extension and implemented show as show _ = show (foo :: a). It's working perfectly. It's nice to know about your asTypeOf approach too.
"I didn't need forall at least." Good to know!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.