Haskell 使用常量值的退化typeclass实例声明

Haskell 使用常量值的退化typeclass实例声明,haskell,typeclass,Haskell,Typeclass,我已经将所有内容简化为基本内容,如果下面的示例代码是人为设计的,请耐心等待。假设我们有: class Foo a where foo :: a data Type a = Type a instance (Foo a) => Foo (Type a) where foo = Type foo 现在,假设我想将Type a作为Show的实例,只要a是Foo和Show的实例(选择Show是为了避免定义另一个typeclass)。那么我们希望类型a如何成为Show的实例呢?

我已经将所有内容简化为基本内容,如果下面的示例代码是人为设计的,请耐心等待。假设我们有:

class Foo a where
    foo :: a

data Type a = Type a

instance (Foo a) => Foo (Type a) where
    foo = Type foo
现在,假设我想将
Type a
作为
Show
的实例,只要
a
Foo
Show
的实例(选择
Show
是为了避免定义另一个typeclass)。那么我们希望
类型a
如何成为
Show
的实例呢?好吧,除非我们疯了,我们当然希望它是这样的

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

instance (Foo a, Show a) => Show (Type a) where
    show (Type x) = "Blabla " ++ (show x)
这一切都很好,效果很好。出于某种莫名其妙的原因,我们希望
show
输出
foo::a
看起来/显示的任何内容!在我们人为的环境中,我无法想象为什么我们会想要这样,但假设我们想要。不应该

instance (Foo a, Show a) => Show (Type a) where
    show _ = show foo
玩这个把戏

唉,GHC说

中不明确的类型变量“a” 约束:“Foo a”[…]”显示a'

也许GHC搞不清我说的是哪个
foo
。我是说
foo::Type a
还是
foo::a
?将上一个代码段更改为

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

无法从 上下文() 因在[…]使用“foo”而产生 可能的解决方案: 将(fooa1)添加到表达式类型签名的上下文中 在'show'的第一个参数中,即'(foo::a)' 在表达式中:show(foo::a)

在这一点上,我开始认为我误解了一些基本的东西。然而,我有一种奇怪的感觉,类似的构造在过去对我起了作用。

我认为问题在于类型变量的作用域并不局限于定义。就是在

instance (Foo a, Show a) => Show (Type a) where
    show _ = show (foo :: a)
第二行中的
a
与第一行中的
a
不同,这就是为什么它在错误消息中显示为
a1
。看见如果这是问题所在,这应该可以工作(我在这台机器上没有GHC):


回答很好,除了一个导致不终止的小错误:最后一行应该是
show(Type x)=show(foo`asTypeOf`x)
。您还可以使用
{-#语言范围的TypeVariables}
以及
show=show(foo::a)
太棒了!谢谢,这真的澄清了问题。还要感谢pelotom指出了GHC扩展。我之所以没有提到该扩展,是因为它需要明确地编写
forall
,但我不确定它应该去哪里:
instance forall a。(Foo a,Show a)=>Show(Type a)
?其他地方?实例不需要?Alexey:至少我不需要所有的
。在我的示例中,我打开了GHC扩展,并将
show
实现为
show.=show(foo::a)
。它工作得很好。很高兴知道你的
asTypeOf
方法。“我不需要
至少所有的
。”很高兴知道!
asTypeOf :: a -> a -> a
asTypeOf a b = a

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