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

为什么有些Haskell函数不抽象具体的积分类型?,haskell,types,polymorphism,Haskell,Types,Polymorphism,例如,函数length抽象具体的序列(Foldable),但不抽象具体的整数类型Int: length :: Foldable t => t a -> Int 下面的类型签名更有用还是更方便 length' :: Foldable t, Integral i => t a -> i 是的,也许,但是首先要注意更多的多态性并不总是一件好事。如果所有函数都具有高度多态性的参数和结果,那么编译器就没有什么信息来开始类型推断,因此您最终不得不键入更笨拙的本地签名 至于leng

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

length :: Foldable t => t a -> Int
下面的类型签名更有用还是更方便

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

是的,也许,但是首先要注意更多的多态性并不总是一件好事。如果所有函数都具有高度多态性的参数和结果,那么编译器就没有什么信息来开始类型推断,因此您最终不得不键入更笨拙的本地签名

至于
length
,没有什么理由让您希望得到任何其他
Integral
类型的结果,但
Int
,至少在64位机器上不是这样:

  • 在Haskell中,像
    Word16
    这样的较小类型通常不会提供太多的性能或内存优势,因为在那里会有一些限制,然后你有一个64位的指针,只指向16位的信息。。。有点傻
  • 基本上不可能有一个列表(更不用说数组或映射)如此之大,以至于它的长度不能用63位的字来衡量。即使对于一个在任何时候都不可能完全存在于内存中的疯狂懒惰列表来说。
    现在,严格地说,
    Int
    只能保证29,在某些极端情况下,这可能会耗尽,但实际上这仅适用于内存和性能更有限的32位平台,所以你不会想处理如此庞大的数据
  • 因此,任何性能或耗竭可能导致问题的应用程序都应该优化为比列表或其他可折叠的
    更有效的应用程序(由于参数化,这些应用程序总是被装箱);未绑定向量或
    ByteString
    s的性能要好得多
  • 如果您需要的结果是
    Integer
    或其他更昂贵的结果,不是因为长度而是简单的上下文原因,那么最好只计算
    Int
    中的长度,并在最后转换一次,而不是在整个列表中拖拽一个缓慢的加法
也就是说,事实上,有时我确实希望签名是

…请注意,函数不需要知道其结果将是积分。事实上,将结果合理化通常非常有用,这样我们就可以编写

average :: Fractional n => [n] -> n
average l = sum l / length l
而不需要integral的额外


前奏曲.length中不是这样的原因是什么?我不知道,似乎有点历史性。其基本原理可能正如我在开始时所说的,您不需要太多多态性。再说一次,在我看来,让函数结果尽可能具有多态性通常是一个好主意,而应该更严格地约束参数,因为这样的话,结果将总是绑定到可以用于类型推断的东西上。

是的,也许,但是首先要注意,更多的多态性并不总是一件好事。如果所有函数都具有高度多态性的参数和结果,那么编译器就没有什么信息来开始类型推断,因此您最终不得不键入更笨拙的本地签名

至于
length
,没有什么理由让您希望得到任何其他
Integral
类型的结果,但
Int
,至少在64位机器上不是这样:

  • 在Haskell中,像
    Word16
    这样的较小类型通常不会提供太多的性能或内存优势,因为在那里会有一些限制,然后你有一个64位的指针,只指向16位的信息。。。有点傻
  • 基本上不可能有一个列表(更不用说数组或映射)如此之大,以至于它的长度不能用63位的字来衡量。即使对于一个在任何时候都不可能完全存在于内存中的疯狂懒惰列表来说。
    现在,严格地说,
    Int
    只能保证29,在某些极端情况下,这可能会耗尽,但实际上这仅适用于内存和性能更有限的32位平台,所以你不会想处理如此庞大的数据
  • 因此,任何性能或耗竭可能导致问题的应用程序都应该优化为比列表或其他可折叠的
    更有效的应用程序(由于参数化,这些应用程序总是被装箱);未绑定向量或
    ByteString
    s的性能要好得多
  • 如果您需要的结果是
    Integer
    或其他更昂贵的结果,不是因为长度而是简单的上下文原因,那么最好只计算
    Int
    中的长度,并在最后转换一次,而不是在整个列表中拖拽一个缓慢的加法
也就是说,事实上,有时我确实希望签名是

…请注意,函数不需要知道其结果将是积分。事实上,将结果合理化通常非常有用,这样我们就可以编写

average :: Fractional n => [n] -> n
average l = sum l / length l
而不需要integral的额外


前奏曲.length中不是这样的原因是什么?我不知道,似乎有点历史性。其基本原理可能正如我在开始时所说的,您不需要太多多态性。再说一次,在我看来,让函数结果尽可能具有多态性通常是一个好主意,而且更严格地约束参数,因为这样的话,结果将总是绑定到可以用于类型推断的东西上。

直觉上,这是因为
可折叠的
带有“长度”大于
2^29-1
的情况非常罕见(而且计算起来非常耗时),因此任何需要它的人都不会介意编写一个快速的
length'=foldl'(\a\u->a+1)0
。请注意genericllength确实存在。@Alec不过它只是为
List
定义的,而不是所有
Foldable
s()。作为直觉,这是因为
Foldable
s带有“length”g