为什么有些Haskell函数不抽象具体的整数类型?

时间:2017-12-30 10:46:59

标签: haskell types polymorphism

例如,函数length抽象具体序列(Foldable),但不抽象具体整数类型Int

length :: Foldable t => t a -> Int

拥有以下类型签名是否更有用或更方便?

length' :: Foldable t, Integral i => t a -> i

1 个答案:

答案 0 :(得分:5)

是的,或许,但是首先请注意,更多的多态性并不总是一件好事。如果所有函数都具有高度多态的参数结果,那么编译器几乎没有信息来启动类型推断,因此您最终必须键入更多笨拙的本地签名。

现在至于length,几乎没有理由说你想要任何其他Integral类型但Int的结果,至少不是64位机器上的结果:

  • Word16这样的较小类型通常不会在Haskell中提供很多性能或内存优势,因为它会有一些拳击somwhere,然后你有一个只有16位信息的64位指针。 ..有点傻。
  • 基本上不可能有一个列表(更不用说数组或映射)如此之大,以至于无法用63位字测量其长度。即使是一个疯狂的懒惰列表,它在任何时候都永远不会完全存在于内存中。
    现在,严格来说,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 设置为尽可能多态,而是更加严格地约束参数,因为这样结果总会被绑定可以用于类型推断的东西。