在ghci
中徘徊,我碰巧注意到表达式(*) 1 [1..5]
显然有一个有效的类型。
:t (*) 1 [1..5]
(*) 1 [1..5] :: (Enum t, Num [t], Num t) => [t]
显然它是一个包含多个类型约束的列表,包括Num [t]
,这对我来说是不可能的,就像它应该给出错误一样。
这是表达式的类型?为什么ghci
的{{1}}命令在此处没有出错?
答案 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
因此1
被fromInteger (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}}