开发者

Degenerate typeclass instance declaration using constant value

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜