为什么这个表达式有一个有效的类型?

时间:2017-09-15 03:54:53

标签: haskell ghci

ghci中徘徊,我碰巧注意到表达式(*) 1 [1..5]显然有一个有效的类型。

:t (*) 1 [1..5]
(*) 1 [1..5] :: (Enum t, Num [t], Num t) => [t]

显然它是一个包含多个类型约束的列表,包括Num [t],这对我来说是不可能的,就像它应该给出错误一样。

这是表达式的类型?为什么ghci的{​​{1}}命令在此处没有出错?

2 个答案:

答案 0 :(得分:10)

Num [t]不仅是可能的,而且很简单:

import Control.Applicative
liftA0 = pure -- hobgoblins, simple minds, etc.
liftA1 = fmap
instance Num t => Num [t] where
    (+) = liftA2 (+)
    (-) = liftA2 (-)
    (*) = liftA2 (*)
    negate = liftA1 negate
    abs    = liftA1 abs
    signum = liftA1 signum
    fromInteger n = liftA0 (fromInteger n)

因此,GHC产生错误而不是推断您的表达式可以通过适当的实例很好地输入是很糟糕的。

当然,在实际代码中编写这个实例也很糟糕,但GHC不应该像我们人类那样对代码进行判断。

答案 1 :(得分:3)

让我们看看这些约束如何解释这种类型。

数字

在Haskell中,一个字面数字会被调用fromInteger(或fromRational,如果它有一个小数点或“' e”)。通过这种方式,人们可以写出' 1'让它浮动或双重或int或其他什么。 fromInteger的类型是

fromInteger :: Num a => a

因此1fromInteger (1::Integer)置于Num t => t类型[a..b]

范围

在Haskell中,语法enumFromTo a b被转换为调用enumFromTo :: Enum a => a -> a -> [a],类型为[1..5] == enumFromTo (fromInteger 1) (fromInteger 5) :: (Enum a, Num a) => [a] 。将这些放在一起我们得到了

(*)

全部放在一起

现在Num b => b -> b -> b的类型是(Num t, Num a, Enum a, Num b, t~b, [a]~b) => b ,所以我们将这些组合在一起得到:

a~b

请注意,a表示b(Num a, Enum a, Num [a]) => [a] 类型相同。组合这些给出类型

{{1}}