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 ())
考虑以下函数:
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 offoo
prevents the constraint(Show a0)
from being solved. Probable fix: use a type annotation to specify whata0
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 ())