4

当我输入

:t map length . sum

进入 GHCi,它说类型是:

map length . sum :: Num [[a]] => [[[a]]] -> [Int]

但是,如果我创建一个type-test.hs包含

x :: Num [[a]] => [[[a]]] -> [Int]
x = map length . sum

ghc 和 ghci 都抱怨:

type-test.hs:1:1:
    Non type-variable argument in the constraint: Num [[a]]
    (Use -XFlexibleContexts to permit this)
    In the type signature for `x': x :: Num [[a]] => [[[a]]] -> [Int]

当未启用 FlexibleContexts 时,为什么 ghci 允许我推断此类型(使用 :t)?

4

5 回答 5

10

首先,让我们澄清一件事。如果我们在 GHCi 中定义函数而不是查询类型会发生什么?

> let x = map length . sum :: (Num [[a]]) => [[[a]]] -> [Int]
<interactive>:0:9:
    Non type-variable argument in the constraint: Num [[a]]
    (Use -XFlexibleContexts to permit this)
    In an expression type signature: Num [[a]] => [[[a]]] -> [Int]

等等。换句话说,同样的事情。如果我们让 GHCi 推断定义的类型呢?

> let x = map length . sum
<interactive>:0:22:
    No instance for (Num [[a0]])
      arising from a use of `sum'
    Possible fix: add an instance declaration for (Num [[a0]])
    In the second argument of `(.)', namely `sum'
    In the expression: map length . sum

这与加载包含没有类型签名的定义的文件所导致的错误大致相同。

这一切的结果是什么?好吧,想想它告诉你需要什么扩展的事实。GHC 能够识别该类型的含义,即使它默认拒绝该类型。我几乎不指望 GHC 会根据所使用的扩展组合使用完全不同的类型检查器,因此似乎很容易得出结论,除了禁用相关扩展之外,无缘无故地拒绝了违规类型。

GHCi 中的:t命令不是编译过程的一部分——它是类型检查和推理系统的热线,让您询问假设代码的类型。它没有明显的理由根据扩展来任意限制自己,因为更通用的类型仍然可以提供信息,原因与上面的错误消息告诉您的原因相同,use -XFlexibleContexts to permit this而不仅仅是syntax error in type constraint.


顺便说一句,可能更有趣的是,在某些情况下,编译器会愉快地接受推断类型,但由于多种原因之一,推断类型实际上不能显式写出。

例如,禁用单态限制将允许您的示例推断其类型(与:t所说的匹配),尽管该类型需要扩展才能手动编写。

另一个例子是where函数定义的子句中的定义,它使用父函数的多态参数。它们自己的类型不是多态的,由外部范围内接收的参数决定,但父函数签名中的类型变量不在子句的范围内where¹。可能还有其他例子。

ScopedTypeVariables¹ 如果需要,可以使用扩展名和显式将来自父签名的类型变量带入范围forall

于 2011-12-14T16:02:58.193 回答
7

(这不回答你原来的问题,而是用代码解决问题)

这些错误暗示您编写的代码可能不是您的意思。这段代码:

map length . sum

意思是“获取我的数字列表,并将其相加,然后计算结果数字的每个元素(??)的长度。” 这是没有意义的。

你可能的意思是:

sum . map length

这意味着“获取我的列表列表,计算每个元素的长度,并对长度求和。”

错误消息本身的意思是,因为sum返回一个数字,也就是sumis的类型Num n => [n] -> n,然后你尝试使用map length它,它有 type Num m => [[a]] -> [m],编译器试图说n == [[a]]使类型匹配,一切都从那里走下坡路.

于 2011-12-14T16:03:53.183 回答
5

另一种看待它的方式:

Haskell 告诉您,您的表达式具有有效类型,即[[[a]]] -> [Int]if only[[a]]Num.

这就像一些女孩告诉你,当地狱结冰时她会和你一起出去。你不会抱怨她答应和我出去尽管地狱可以冻结这个世界上没有可能性,对吗?你宁愿注意到她只是以或多或少的礼貌方式说“不”。

于 2011-12-14T17:19:26.493 回答
1

问题是该函数完全可以接受,但语言语法不允许指定其最通用的类​​型。ghci在这种情况下能做什么?我只能想到两个选项,要么给出一个只能在启用某些扩展的情况下指定的类型,要么给出一个错误。给出一个错误而不提及可以通过启用扩展来修复它对我来说似乎不是很可取。仅仅:t报告推断的最通用类型就更简单了,而且很可能在实现该功能时,没有人想到这样的情况。

于 2011-12-14T16:19:28.773 回答
0

请参阅http://haskell.org/ghc/docs/6.12.1/html/users_guide/interactive-evaluation.html#extended-default-rules

于 2011-12-14T16:02:07.610 回答