Haskell: "ambiguous type variable arising from using a function",其中所说的变量实际上无关紧要

Haskell: "ambiguous type variable arising from using a function", where said variable actually doesn't matter

考虑以下函数:

foo :: Show a => Maybe a -> [Char] 
foo (Just x) = show x 
foo Nothing = "Nothing"

那我试试用这个功能:

bar :: [Char]
bar = foo Nothing

传递给foo的参数是Maybe a类型,其中a没有指定,实际上我们不关心a,因为对于 Nothing,我们只使用 foo 的情况。但是GHC声称提供了具体的类型:

Ambiguous type variable a0 arising from a use of foo
prevents the constraint (Show a0) from being solved. Probable fix: use a type annotation to specify what a0 should be.

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"

它有效,但似乎非常简单。但我不喜欢这个解决方案的真正原因是因为出于我的目的,这段代码是从一些元数据自动生成的,它没有提供关于哪种特定多态类型必须指定为 Dummy 的信息(有可能是具有多个参数的用户数据类型)。所以我想知道,有没有什么办法可以告诉 GHC,如果没有指定类型,这个类型无关紧要?

"doesn't matter" 是实例的 属性 ,而 ghc 不会像那样内省实例。对于某些类型,它确实很重要。 [a]Show 实例取决于类型 a,即使列表为空也是如此。查看 show ([] :: [Char]) 的结果与 show ([] :: [Int]).

的结果

但所有这些都算是题外话了。事实上,类型是在编译时确定的,但值是在 运行 时确定的。您提出了一种情况,其中类型变量仅对某些输入值无关紧要。在这种情况下,类型变量仍然很重要,因为它们控制其他情况下的行为。

您将必须正确解析不明确的类型,因为这就是 ghc 知道要使用哪个代码的方式。有一些技术可以方便地做到这一点,比如使用 ScopedTypeVariables 扩展,但如果没有更具代表性的代码片段,很难推荐一种技术。不过,我能说的最重要的事情是它确实很重要,因为实例选择是在编译时完成的,远远早于看到一个值。

类型检查器不知道 foo 对其参数做了什么,尤其不知道 Nothing 实际上不会被使用。但它确实知道参数必须具有类型Show a => Maybe a,并且Nothing具有更通用的类型Maybe a。在调用 foo.

时,由您提供类型足够窄的参数

无需定义新的虚拟类型;任何具有 Show 实例的现有类型都可以。

bar :: [Char]
bar = foo (Nothing :: Maybe ())