Haskell简介,98版
后面 下一个 顶部


10  数字

Haskell基于方案[7],这反过来又基于CommonLisp语言[8]。(然而,这些语言是动态类型。)标准类型包括固定和任意决定整数,比率(有理数)由每个整数类型,以及单精度和双精度实数和复数浮点。我们在这里概述了数字类型类结构,并让读者参考§6.4了解详细信息。

10.1  数字类结构

数字类型类(类号码以及它下面的那些)对…负有责任许多标准Haskell类。我们还注意到号码是的子类等式,但不是的订单; 这是因为订单谓词不适用于复数。子类真实的属于号码但是,是的一个子类订单也。

这个号码类提供了几种通用的基本操作数字类型;其中包括加法、减法、,否定、乘法和绝对值:

(+),(-),(*)::(数字a)=>a->a->a
取反,abs::(数字a)=>a->a

[否定是Haskell唯一的前缀操作符应用的函数,负;我们不能称之为(-),因为这是减法函数,因此改为提供此名称。例如,-x年等于取反(x*y)。(前缀minus相同作为中缀减号的句法优先顺序,当然是较低的而不是乘法。)]

请注意号码提供除法运算符;在两个非重叠区域中提供了不同类型的除法运算符的子类号码:

这个班级完整的提供整数除法和余数操作。这个的标准实例完整的整数(无边界或数学整数,也称为“bignums”)和国际(有界机器整数,范围至少等于29位有符号二进制)。特定的Haskell实现可能除此之外,还提供其他积分类型。请注意完整的是的子类真实的,而不是号码直接;这意味着没有尝试提供高斯整数。

所有其他数字类型都属于该类分数的,它提供普通除法算子(/).进一步的子类浮动包含三角函数、对数函数和指数函数。

这个RealFrac公司的子类分数的真实的提供了一个函数适当分数,它将数字分解为整数小数部分,以及四舍五入到不同规则的积分值:

properFraction::(分数a,积分b)=>a->(b,a)
截形、圆形、,
地板、天花板::(分数a、积分b)=>a->b

这个RealFloat公司的子类浮动RealFrac公司提供有效访问组件的一些专用功能对于浮点数指数有效数.标准类型浮子双精度上课时跌倒RealFloat公司.

10.2  构造的数字

在标准数字类型中,国际,整数,浮子、和双精度是原始的。其他的是由这些按类型构造函数生成的。

复杂(在图书馆里找到复杂)是一个类型构造函数在类中生成复杂类型浮动来自RealFloat公司类型:

data(RealFloat a)=>复杂a=!a:+!a推导(等式、文本)

这个!符号是严格标志;这些在第节中进行了讨论6.3.注意上下文RealFloat实际浮动,它限制了参数类型;因此,标准复合类型是复杂浮点复合双精度。我们也可以从中看到数据宣言写一个复数x个 :+ ; 这些参数是笛卡尔实部和虚部。:+是一个数据构造函数,我们可以在模式匹配中使用它:

共轭::(RealFloat a)=>复数a->复数
共轭(x:+y)=x:+(-y)

类似地,类型构造函数比率(位于理性库)在类中创建有理类型RealFrac公司来自的实例完整的. (理性是的类型同义词比率整数.)比率然而,它是一个抽象类型构造函数。而不是像这样的数据构造函数:+,理性使用`%'函数到从两个整数构成一个比率。而不是模式匹配,提供了组件提取功能:

(%)::(积分a)=>a->a->比率a
分子、分母::(积分a)=>比率a->a

为什么不同?笛卡尔形式的复数是独特——不存在涉及:+。在另一方面,比率不是唯一的,而是标准(简化)形式抽象数据类型的实现必须维护;它是不一定是这样,例如分子(x%y)等于x个,尽管是x: +年总是x个.

10.3  数字强制和过载文字

标准前奏曲和库提供了几个重载函数作为明确的胁迫:

fromInteger::(数字a)=>整数->a
fromRational::(分数a)=>Rational->a
toInteger::(整数a)=>a->Integer
toRational::(RealFrac a)=>a->Rational
fromIntegral::(积分a,数字b)=>a->b
fromRealFrac::(RealFrac a,分数b)=>a->b

fromIntegral=fromInteger。到整数
fromRealFrac=来自Rational。到理性

其中两个隐式地用于提供重载的数字文字:整数(不带小数点)实际上等于的应用程序from整数数字的值作为整数。类似地,浮点数(带小数点)为被视为来自Rational到的值数字作为理性因此,7具有类型(数字a)=>a,7.3具有类型(分数a)=>a这意味着我们可以在通用数字函数中使用数字文字,例如:

减半::(分数a)=>a->a
减半x=x*0.5

这种相当间接的重载数字的方法有额外的将数字解释为数字的方法的优点可以在完整的分数的实例声明(自from整数来自Rational这些类的运算符)。例如号码的实例(RealFloat a)=>Complex复杂包含此方法:

fromInteger x=from整数x:+0

这说明复杂的实例from整数定义为生成一个复数,其实数部分由适当的RealFloat公司的实例from整数以这种方式,甚至用户定义的数值类型(例如四元数)可以利用重载的数字。

再举一个例子,回顾一下我们对inc公司来自节2:

inc::Integer->整数
inc n=n+1

忽略类型签名inc公司(数字a)=>a->a。显式类型签名合法,然而,因为它是更具体的比主要类型(a更通用的类型签名将导致静态错误)。类型签名具有限制作用inc公司的类型,在此这种情况会导致如下情况inc(1::浮点)待输入。

10.4  默认数字类型

考虑以下函数定义:

rms::(浮动a)=>a->a->a->a
rms x y=平方((x^2+y^2)*0.5)

指数函数(^)(三种不同标准之一不同类型的求幂运算符,见报告第6.8.5节)类型(数字a,积分b)=>a->b->a,自2类型(数字a)=>a,类型x ^2(x ^2)(数字a,积分b)=>a.这是一个问题;无法解决过载问题与类型变量关联b,因为它是在上下文中,但是已从类型表达式中消失。本质上程序员已指定x个应该平方,但还没有指定是否应与国际或一个整数值为2。当然,我们可以解决这个问题:

rms x y=平方((x^(2::整数)+y^(2::整数))*0.5)

然而,很明显,这种事情很快就会变得令人厌烦。

事实上,这种重载歧义不仅限于数字:

显示(读取“xyz”)

字符串应该以什么类型读取?这是比指数模糊性更严重,因为完整的实例就可以了,而在这里,行为却大不相同取决于的哪个实例文本习惯于解决歧义。

由于重载歧义问题,Haskell提供了一个解决方案限制为数字:每个模块可以包含一个违约宣言,包含关键字违约后跟一个带括号、逗号分隔的数字单类型列表(具有无变量)。当发现不明确的类型变量时(例如b,上面的),如果它的至少一个类是数字的,并且它的所有类类是标准的,参考默认列表,第一个将满足类型变量上下文的列表中的类型使用。例如,如果默认声明默认值(Int、Float)则上述模糊指数将被解析为类型国际(请参见§4.3.4了解更多详细信息。)

“默认默认值”为(整数,双精度),但是(整数、有理数、双精度)也可能是适当的。非常谨慎程序员可能更喜欢默认(),不提供默认值。


Haskell简介,98版
后面 下一个 顶部