Haskell混合数字类型的运算

Haskell混合数字类型的运算

Num是数字类型,可以进行数字所支持的运算。在Num类的类成员中还有Int, Integer, Float, Double这些类,这些类成员同样可以执行运算,比如对于乘法,函数签名为

Prelude> :t (*)
(*) :: Num a => a -> a -> a

说明这个乘法运算在Num约束下的类型a进行,对于两个a类型的运算得到一个a类型的结果。例如

Prelude> 20*1.5
30.0
Prelude> :t (20*1.5)
(20*1.5) :: Fractional a => a

其它四则运算的函数签名与乘法的函数签名类似。不过要注意的是,参与运算的必须是相同的Num约束的类型,例如必须是Int与Int相乘,而若是使用Int与Integer相乘就会出错:

Prelude> (5::Int)*(6::Int)
30
Prelude> (5::Int)*(6::Integer)
<interactive>:13:11:
    Couldn't match expected type ‘Int’ with actual type ‘Integer’
    In the second argument of ‘(*)’, namely ‘(6 :: Integer)’
    In the expression: (5 :: Int) * (6 :: Integer)
    In an equation for ‘it’: it = (5 :: Int) * (6 :: Integer)

将两运算数5和6分别视为Int和Integer类型,这个*运算就会因为类型与签名无法匹配而报错。而更多的是有Floating参与的情况因为经常需要整数与小数相乘,如果不是常数(数字会认为是Num类型,自动进行类型推导)那么不同类型之间就无法进行运算。

Integral是整数数字的类型约束,Int和Integer都是其类成员,Floating是浮点数的类型约束,Float和Double都是其类型成员。如果我们有几个函数结果的类型不同,而这些类型之间需要运算,对于Integral的整数类就需要用将之转换为Num类

Prelude> :t fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b

fromIntegral会将Integral类约束的a类型转换为Num约束的b类型,在参与运算时,Num类型与Num约束下的类型就可以合理的进行类别推导,从而完成运算。

Prelude> (5::Int)/(3.2::Double)
<interactive>:21:11:
    Couldn't match expected type ‘Int’ with actual type ‘Double’
    In the second argument of ‘(/)’, namely ‘(3.2 :: Double)’
    In the expression: (5 :: Int) / (3.2 :: Double)
    In an equation for ‘it’: it = (5 :: Int) / (3.2 :: Double)
Prelude> (fromIntegral (5::Int))/(3.2::Double)
1.5625
Prelude> :t (fromIntegral (5::Int))/(3.2::Double)
(fromIntegral (5::Int))/(3.2::Double) :: Double

fromIntegral将Int类转化为Num类,而Num类与Double进行运算时类型会推导成Double与Double的运算,结果为Double类,就可以实现不同类型数据之间的运算。

最后用一个实例,运用一下fromInteger,用于计算一个浮点数的数值与这个数字的字符长度之比:

main = do
    line<-getLine
    let value = read line :: Double
    let strLen = length $ line
    print $ (value) / (fromIntegral strLen)

发表评论

电子邮件地址不会被公开。 必填项已用*标注