Haskell 为度量数据结构的函数指定什么类型?整数,整数,整数?

Haskell 为度量数据结构的函数指定什么类型?整数,整数,整数?,haskell,Haskell,我有一个数据结构,比如表达式树或图。我想添加一些“测量”功能,例如深度和大小 如何最好地键入这些函数 我认为以下三种变体的作用大致相同: depth::Expr->Int depth::Expr->Integer depth::Num a=>Expr->a 我有以下考虑: 我以base和fgl为例,它们一贯使用Int,但使用数据。List还具有genericlelength等返回类型多态的函数,我在想,也许这些通用函数的增加反映了一种现代化趋势,我可能应该尊重和加强这一趋势 在一些广泛使用

我有一个数据结构,比如表达式树或图。我想添加一些“测量”功能,例如
深度
大小

如何最好地键入这些函数

我认为以下三种变体的作用大致相同:

  • depth::Expr->Int
  • depth::Expr->Integer
  • depth::Num a=>Expr->a
我有以下考虑:

  • 我以
    base
    fgl
    为例,它们一贯使用
    Int
    ,但使用
    数据。List
    还具有
    genericlelength
    等返回类型多态的函数,我在想,也许这些通用函数的增加反映了一种现代化趋势,我可能应该尊重和加强这一趋势

  • 在一些广泛使用的库中,当用户需要返回类型的多个可能选择时,可以看到类似的思想运动,这些库提供具有相同功能的综合功能集(例如,
    xml管道
    提供的解析器既可以接受惰性的,也可以接受严格类型的
    ByteString
    文本

  • Integer
    是一种比
    Int
    更好的类型,有时我发现我需要将列表的长度转换为
    整数,比如说,因为在
    Integer
    中运行的算法需要考虑这个长度

  • 使函数返回
    Integral
    意味着这些函数是多态的,可能会有性能损失。我不太清楚所有细节,但据我所知,可能会有一些运行时成本,多态的东西更难记忆


什么是公认的最佳实践?哪一部分是由于遗留和兼容性考虑?(即,如果
Data.List
是今天设计的,那么
length
等函数会有什么类型?)我错过了任何优点和缺点吗?

简短的回答:通常使用
Int
,如果需要将其转换为其他内容,请使用
fromIntegral
(如果您发现自己经常进行转换,请定义
fi=fromIntegral
以保存键入内容,或者创建自己的包装器。)

主要考虑的是性能。您希望编写算法,以便在内部使用有效的整数类型。前提是
Int
对于您正在进行的任何计算都足够大(标准保证有符号30位整数,但即使在使用GHC的32位平台上,它也是有符号32位整数),您可以假设它将是平台上的高速整数类型,特别是与
integer
相比(它具有无法优化的装箱和bignum计算开销)。请注意,性能差异可能很大。使用
Int
s与
Integer
s相比,简单的计数算法通常会快5-10倍

虽然您可以为您的函数提供不同的签名:

depth :: Expr -> Integer
depth :: (Num a) => Expr -> a
但实际上,使用高效的
Int
类型在引擎盖下实现它,并在最后进行转换,使转换隐式让我觉得这是一个糟糕的做法。特别是如果这是一个库函数,那么让我感觉更为敏感的是,通过使其成为签名的一部分,可以清楚地表明
Int
正在内部使用e

关于您列出的注意事项:

首先,
Data.List
中的
generic*
函数并不现代。特别是,
genericlelength
于1996年7月发布。在此之前,
length
已根据
genericlelength
定义为:

length :: [a] -> Int
length = genericLength
但在GHC 0.29中,这一定义被注释为
#ifdef USE_REPORT_PRELUDE
,几个手动优化的
长度变量独立定义。其他
通用*
函数不在0.29中,但GHC 4.02(1998年)已经存在

最重要的是,当
Prelude
版本的
length
从列表推广到
Foldable
s,这是一个相当新的发展(自GHC 7.10?)时,没有人关心如何使用
genericlelength
。我也不认为“在野外”使用过这些函数在任何严肃的Haskell代码中。在大多数情况下,您可以认为它们已被弃用

其次,在库中使用lazy/strict和
ByteString
/
Text
变体代表了一种不同的情况。特别是,
管道xml
用户通常会根据考虑在lazy和strict变体之间以及
ByteString
Text
类型之间做出决定关于正在处理的数据和算法的构造,这些算法影响深远,并渗透到给定程序的整个类型系统中。如果将
导管xml
与惰性
文本
类型一起使用的唯一方法是将其逐段转换为严格的
ByteString
s,则将其传递给库,然后将其从d将其转换回惰性
文本类型,没有人会接受这种复杂性。相反,基于单态
Int
深度定义可以很好地工作,因为您只需要
fromInteger.depth
将其适应任何数字上下文

第三,如上所述,
Integer
只是一种“更好”的类型,因为在您不关心性能的情况下,它具有任意精度。对于任何实际设置中的
depth
count
等内容,性能可能比无限精度更重要

第四,我不认为e
data Integer = SmallInteger Int | LargeInteger ByteArray