考虑以下功能:
foo :: Show a => Maybe a -> [Char]
foo (Just x) = show x
foo Nothing = "Nothing"
Run Code Online (Sandbox Code Playgroud)
然后我尝试使用这个功能:
bar :: [Char]
bar = foo Nothing
Run Code Online (Sandbox Code Playgroud)
已传递给参数foo的类型是Maybe a其中a没有指定,而事实上,我们不关心a,因为我们只使用的情况下foo进行的Nothing.但GHC声称提供具体类型:
a0由于使用而产生的模糊类型变量foo
可防止约束(Show a0)被解决.可能的修复:使用类型注释来指定a0应该是什么.
GHC提示指定类型.所以我看到的唯一修复就是创建一个伪类型,它有一个Show类型为class 的实例:
{-# 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"
Run Code Online (Sandbox Code Playgroud)
它有效,但似乎非常简单.但是我不喜欢这个解决方案的真正原因是因为我的目的,这个代码是从一些元数据自动生成的,它不提供必须指定哪个特定多态类型的信息Dummy(可能有用户数据类型)有多个参数).所以我想知道,有没有办法告诉GHC,如果没有指定类型,这种类型无关紧要?
"无关紧要"是实例的属性,而ghc并不反省这样的实例.对于某些类型,它确实很重要.该Show例如[a]取决于类型a,即使该列表是空的.查看show ([] :: [Char])vs的结果show ([] :: [Int]).
但所有这一切都有点搁置.事实是,类型是在编译时确定的,但值是在运行时确定的.您已经提出了一种情况,类型变量对于某些输入值无关紧要.在这种情况下,类型变量仍然很重要,因为它们控制其他情况下的行为.
你将不得不正确地解决模糊类型,因为ghc知道使用哪个代码.有一些方便的方法,比如使用ScopedTypeVariables扩展,但很难推荐一个没有更具代表性的代码.我能说的最重要的事情是它确实很重要,因为实例选择是在编译时完成的,早在看到值之前很久.
类型检查器不知道foo它的参数做了什么,特别是不知道它Nothing实际上不会被使用。但它确实知道参数必须具有类型Show a => Maybe a,并且Nothing具有更通用的类型Maybe a。在调用foo.
无需定义新的虚拟类型;任何带有Show实例的现有类型都可以。
bar :: [Char]
bar = foo (Nothing :: Maybe ())
Run Code Online (Sandbox Code Playgroud)