Haskell列表的类型错误

5
在GHCi中,我输入:
let xs = [1, 'a']

它会立即报错:

<interactive>:28:11:
No instance for (Num Char) arising from the literal ‘1In the expression: 1
In the expression: [1, 'a']
In an equation for ‘xs’: xs = [1, 'a']

然而,当我输入

let xs = [1, [1, 1]]

刚才已经通过了。但是当我尝试打印xs时出现错误提示:

<interactive>:5:1:
No instance for (Num [t0]) arising from a use of ‘it’
In a stmt of an interactive GHCi command: print it

我认为Haskell是一种静态类型语言,因此任何类型错误都应该在编译时捕获。我想知道为什么上述两个错误在不同的时间被捕获?

1个回答

8
1是类型为Num a => a的多态值。因此,在[1,[2,3]]中,我们有[2,3] :: Num a => [a];由于所有列表元素必须具有相同的类型,我们得出结论,必须有1 :: Num a => [a]。这有点奇怪 - 把1看作具有列表类型很奇怪 - 但是如果有人创建了足够奇怪的Num实例,则可以完全有效。检查实例是否存在推迟到尝试使用该实例时进行;这给您定义值后使用实例定义实例的机会。因此,在您尝试实际使用列表[1,[2,3]]之前,它不会发出警告。

举个例子,你可以编写:

instance Num a => Num [a] where
    fromInteger n = pure (fromInteger n)
    (+) = liftA2 (+)
    (-) = liftA2 (-)
    (*) = liftA2 (*)
    abs    = liftA abs
    signum = liftA signum

实际上,这个实例适用于任何 Applicative,有时甚至非常有用。然后,在 ghci 中:

> let xs = [1, [1, 1]]
> xs
[[1],[1,1]]

看,没有错误!


3
为什么同样的推理不能适用于一个潜在的“Num Char”实例呢? - Reid Barton
@ReidBarton 很好的问题!实际上我不确定。我猜在实例解析期间,GHC 拒绝延迟查找单态约束的证据;但这只是一个猜测。 - Daniel Wagner
你可以基于 Enum Char 实例定义一个 Num Char 实例。同样的推理也适用,但此处未包含该实例。 - Jeremy List
1
@DanielWagner,听起来很有道理,我猜它不会急切地解决多态情况下的约束条件的原因不是因为你可能稍后定义一个实例Num [a](对于Num Char也是如此),而是因为(使用FlexibleInstances)可能存在一些特定的实例,例如Num [Double],然后您可以将xs用作类型[[Double]]。换句话说,GHC还不知道要尝试解决什么约束条件。 - Reid Barton
这对我来说有点太深奥了,我只是一个FP的初学者...需要时间消化你的答案。不管怎样,非常感谢。 - Cherish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接