haskell - GHCi 中的类型推断与手动签名

标签 haskell type-inference ghc ghci

当我打字时

: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)?

最佳答案

首先,让我们澄清一件事。如果我们在 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 会根据所用扩展的组合使用完全不同的类型检查器,因此似乎很容易得出结论,除了相关扩展被禁用之外,无缘无故地拒绝了有问题的类型。
:t GHCi 中的命令不是编译过程的一部分——它是类型检查和推理系统的热线,让您询问假设代码的类型。当更通用的类型仍然可以提供信息时,它没有明显的理由根据扩展来任意限制自己,原因与上面的错误消息告诉您的原因相同 use -XFlexibleContexts to permit this而不仅仅是syntax error in type constraint .

除了可能更有趣的是,也有一些情况,编译器会很乐意接受推断类型,但由于多种原因之一,推断类型实际上无法显式写出。

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

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

¹ 来自父签名的类型变量可以通过 ScopedTypeVariables 进入作用域。扩展名和显式 forall ,如果需要的话。

关于haskell - GHCi 中的类型推断与手动签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8507288/

相关文章:

haskell - 如何在单个函数中执行多个语句?

c - Haskell Foldr C 实现

haskell - 为什么 ghci 输出 (Num a) => a for :t 4 and not (Ord a) => a?

Java 8 : generic type inference fails on method reference?

haskell - 函数签名如何匹配请求的类型

haskell - 无法实例化种类多态类型

haskell - DuplicateRecordFields 和函数组合

haskell - 仍然对 GHCi 中的 'let' 感到困惑

ghc - 使用 foldl', foldr 列出连接

Haskell 字符串分词器函数