考虑以下功能:
foo :: Show a => Maybe a -> [Char]
foo (Just x) = show x
foo Nothing = "Nothing"
然后我尝试使用此功能:
bar :: [Char]
bar = foo Nothing
已传递给foo
的参数的类型为Maybe a
,其中未指定a
,实际上我们不在乎a
,因为我们使用foo
仅Nothing
的情况。但是GHC声称提供了具体的类型:
使用
a0
引起的模棱两可的类型变量foo
阻止约束(Show a0)
被解决。可能 修复:使用类型注释来指定a0
应该是什么。
GHC提示指定类型。因此,我看到的唯一解决方法是创建一个伪类型,该类型具有Show
类型类的实例:
{-# LANGUAGE EmptyDataDecls, KindSignatures #-}
{-# OPTIONS_GHC -fno-warn-missing-methods #-}
data Dummy :: *
instance Show Dummy
bar :: [Char]
bar = foo (Nothing :: Maybe Dummy)
foo :: Show a => Maybe a -> [Char]
foo (Just x) = show x
foo Nothing = "Nothing"
它可以工作,但是看起来非常简单。但是,我不喜欢这种解决方案的真正原因是,出于我的目的,该代码是从某些元数据自动生成的,该元数据不提供有关必须将哪种特定的多态类型指定为Dummy
的信息(可能是具有多个参数的用户数据类型)。所以我想知道,有没有办法告诉GHC,如果未指定类型,则此类型无关紧要?
答案 0 :(得分:8)
“无关紧要”是实例的属性,而ghc不会自省这样的实例。对于某些类型,这确实很重要。 Show
的{{1}}实例取决于类型[a]
,即使列表为空。检查a
与show ([] :: [Char])
的结果。
但是所有这些都放在一边。事实是,类型是在编译时确定的,而值是在运行时确定的。您提出了一种情况,其中类型变量仅对某些输入值无关紧要。在这种情况下,类型变量仍然很重要,因为它们在其他情况下控制行为。
您将必须正确解析不明确的类型,因为ghc知道使用哪种代码。有一些技术可以很方便地做到这一点,例如使用ScopedTypeVariables扩展,但是如果没有更具代表性的代码,很难推荐一种方法。我能说的最重要的事情是,它确实很重要,因为实例选择是在编译时完成的,而且早在看到值之前。
答案 1 :(得分:4)
类型检查器不知道foo
对它的参数有什么作用,特别是不知道实际上不会使用Nothing
。但是确实知道参数必须具有类型Show a => Maybe a
,并且Nothing
具有更一般的类型Maybe a
。由您自己决定,在调用foo
时提供一个狭窄的参数。
无需定义新的虚拟类型。任何具有Show
实例的现有类型都可以。
bar :: [Char]
bar = foo (Nothing :: Maybe ())