gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 12:14:25 25 4
gpt4 key购买 nike

考虑以下代码片段,它定义了一个函数 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 []

但出现以下错误:
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 []

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

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

最佳答案

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

foo :: Ord a => [a] -> [a]

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

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

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

或使用新的 TypeApplications 扩展
null (foo @Integer [])

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

注意 foo ([] :: Ord a => [a]) 并没有消除歧义,因为不知道你要传递哪个具体的 Ord 字典;是 Ord Int 还是 Ord (Maybe String) 等?没有通用的 Ord字典,所以我们必须选择,而且这种情况下选择什么类型没有规则。而当你说 (Ord a, Num a) => [a] 时,默认指定了一种选择方式,我们选择 Integer ,因为它是 Num 类的特例。
foo []ghci 中起作用的事实是由于 ghciextended defaulting 规则。一般而言,关于 type defaulting 的内容可能值得一读,这肯定不是 Haskell 最漂亮的部分,但它会在您询问的各种极端情况下出现很多。

关于haskell - 空列表测试中的歧义类型变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49339042/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com