空列表测试中的歧义类型变量

AlQ*_*ist 3 haskell empty-list

考虑以下代码片段,它定义了一个函数foo,该函数接受一个列表并对列表执行一些操作(如排序)。我尝试将片段加载到ghci

-- a function which consumes lists and produces lists
foo :: Ord a => [a] -> [a]
foo [] = []
foo (x:xs) = xs

test1 = foo [1, 2, 3] == [2, 3]
test2 = null $ foo []
Run Code Online (Sandbox Code Playgroud)

但出现以下错误:

No instance for (Ord a0) arising from a use of ‘foo’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance (Ord a, Ord b) => Ord (Either a b)
        -- Defined in ‘Data.Either’
      instance forall (k :: BOX) (s :: k). Ord (Data.Proxy.Proxy s)
        -- Defined in ‘Data.Proxy’
      instance (GHC.Arr.Ix i, Ord e) => Ord (GHC.Arr.Array i e)
        -- Defined in ‘GHC.Arr’
      ...plus 26 others
    In the second argument of ‘($)’, namely ‘foo []’
    In the expression: null $ foo []
    In an equation for ‘test2’: test2 = null $ foo []
Run Code Online (Sandbox Code Playgroud)

问题出在表达式上test2 = null $ foo []。此外,Ord a从 的类型定义中删除约束foo将解决问题。奇怪的是,null $ foo []交互模式下输入(在加载 的定义之后foo)工作正常并产生预期的true.

我需要对这种行为做出明确的解释。

luq*_*qui 6

我喜欢在“字典传递风格”中考虑类型类。签名

foo :: Ord a => [a] -> [a]
Run Code Online (Sandbox Code Playgroud)

说这foo需要一个方法字典Ord a,本质上作为一个参数,和一个as的列表,并返回一个as的列表。字典里有像(<) :: a -> a -> Bool和它的表亲一样的东西。当我们调用 时foo,我们需要提供这样一个字典。这是由编译器隐式完成的。所以

foo [1,2,3]
Run Code Online (Sandbox Code Playgroud)

将使用Ord Integer字典,因为我们知道aInteger

但是,在 中foo [],列表可以是任何内容的列表——没有确定类型的信息。但是我们仍然需要找到Ord要传递给的字典foo(尽管您foo根本不使用它,但签名说它可以,这才是最重要的)。这就是为什么会出现模棱两可的类型错误。您可以手动指定类型,这将提供足够的信息来填写字典,像这样

null (foo ([] :: [Integer]))
Run Code Online (Sandbox Code Playgroud)

或使用新TypeApplications扩展名

null (foo @Integer [])
Run Code Online (Sandbox Code Playgroud)

如果您删除Ord约束,它会起作用,正如您所观察到的,这只是因为我们不再需要提供字典。我们不再需要知道a要调用什么特定类型foo(这对我来说有点神奇:-)。

请注意,这foo ([] :: Ord a => [a])不能消除歧义,因为不知道Ord要传递哪个特定字典;是Ord Int还是Ord (Maybe String)等等?有没有通用的Ord字典,所以我们要选择,有没有什么类型在这种情况下,选择规则。而当您说 时(Ord a, Num a) => [a],则默认指定了一种选择方式,我们选择了Integer,因为它是Num该类的特例。

这一事实foo []在作品ghci是由于ghci扩展的默认规则。一般而言,关于类型默认值的阅读可能值得一读,这肯定不是 Haskell 最漂亮的部分,但它会在您询问的各种极端情况下出现很多。