例如,函数length
抽象具体序列(Foldable
),但不抽象具体整数类型Int
:
length :: Foldable t => t a -> Int
拥有以下类型签名是否更有用或更方便?
length' :: Foldable t, Integral i => t a -> i
答案 0 :(得分:5)
是的,或许,但是首先请注意,更多的多态性并不总是一件好事。如果所有函数都具有高度多态的参数和结果,那么编译器几乎没有信息来启动类型推断,因此您最终必须键入更多笨拙的本地签名。
现在至于length
,几乎没有理由说你想要任何其他Integral
类型但Int
的结果,至少不是64位机器上的结果:
Word16
这样的较小类型通常不会在Haskell中提供很多性能或内存优势,因为它会有一些拳击somwhere,然后你有一个只有16位信息的64位指针。 ..有点傻。Int
只能保证29在某些极端情况下可以用尽,但实际上这只与32相关。这些平台的内存和性能都比较有限,因此您不希望处理如此庞大的数据。Foldable
更有效的东西(由于参数化而总是装箱) ;未装箱的向量或ByteString
的表现要好得多。Integer
或其他更昂贵的东西,不是为了长度而是出于上下文原因,最好只计算Int
中的长度并转换一次< em>在最后,而不是在整个列表中拖动缓慢添加。那就是说,事实上我有时希望签名实际上是actually existing
的签名genericlength :: (Foldable t, Num i) => t a -> i
...请注意,该函数不需要知道其结果将是整数。事实上,使结果理性通常非常有用,所以我们可以编写
average :: Fractional n => [n] -> n
average l = sum l / length l
而不是需要额外的fromIntegral
。
Prelude.length
中不是这种情况的原因?我不知道,似乎颇具历史性。理由可能正如我在开始时所说的那样,你不希望过多的多态性。再说一遍,IMO通常最好将函数 results 设置为尽可能多态,而是更加严格地约束参数,因为这样结果总会被绑定可以用于类型推断的东西。