为什么有些Haskell函数不抽象具体的整数类型?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么有些Haskell函数不抽象具体的整数类型?相关的知识,希望对你有一定的参考价值。
例如,函数length
抽象具体序列(Foldable
),但不抽象具体整数类型Int
:
length :: Foldable t => t a -> Int
拥有以下类型签名会更有用或更方便吗?
length' :: Foldable t, Integral i => t a -> i
答案
是的,或许首先要注意的是,更多的多态性并不总是一件好事。如果所有函数都具有高度多态的参数和结果,那么编译器几乎没有信息来启动类型推断,因此您最终必须键入更多笨拙的本地签名。
现在至于length
,没有理由为什么你想要任何其他Integral
类型的结果,但Int
,至少不是在64位机器上:
- 像
Word16
这样的较小类型通常不会在Haskell中提供很多性能或内存优势,因为它会有一些拳击somwhere,然后你有一个只有16位信息的64位指针......有点傻。 - 基本上不可能有一个列表(更不用说数组或映射)如此之大,以至于无法用63位字测量其长度。即使是一个疯狂的懒惰列表,它在任何时候都永远不会完全存在于内存中。
现在,严格来说,
Int
只能保证29在某些极端情况下可以用尽,但实际上这仅适用于32位平台,无论如何在内存和性能方面都有所限制,所以你不想要处理如此庞大的数据。 - 就此而言,性能或耗尽可能成为问题的任何应用程序都应该优化为比列表或其他
Foldable
更有效的东西(由于参数化而总是装箱);未装箱的载体或ByteString
s表现更好。 - 如果你需要结果是
Integer
或其他更昂贵的东西,不是为了长度而只是上下文的原因,可能更好的想法只是计算Int
的长度并在最后转换一次,而不是拖延一个缓慢的加法整个清单。
也就是说,我确实有时希望签名实际上是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通常最好将函数结果尽可能地变为多态,而是更严格地约束参数,因为这样结果总是会绑定到可以用于类型推断的东西。
以上是关于为什么有些Haskell函数不抽象具体的整数类型?的主要内容,如果未能解决你的问题,请参考以下文章