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 b开发者_JAVA百科asic. Yet, I have the strange feeling that similar constructions have worked for me in the past.
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)
精彩评论