我按照这个答案中的建议开始学习 Haskell 。所以我只是在实现简单的列表函数,我偶然发现了编译器行为的差异,我无法向自己解释:
-- Impl 1
elementAt :: (Integral b) => [a] -> b -> a
elementAt xs id = xs !! (fromIntegral(id-1))
-- Impl 2
elementAt' :: (Num b) => [a] -> b -> a
elementAt' xs id = xs !! (id-1)
带有以下签名:
fromIntegral :: (Integral a, Num b) => a -> b
(!!) :: [a] -> Int -> a
我只收到第二个实现的错误,elementAt'
.
Could not deduce (b ~ Int)
from the context (Num b)
如果我理解正确,这意味着运算符 (!!) 期望Int实例作为其第二个参数(从签名中可以看出),但我们只保证提供的参数符合NumelemenAt'
类型类(从签名中推断) ,它比Int更宽。
考虑到这一点,我不明白为什么第一个实现实际上有效,因为我知道它fromIntegral
也返回一个仅符合Num类型类的值。