2012-10-24 19 views
1

这里是一个函数,一对积分 值和将其划分:如何划分一对Num值?

divide_v1 :: Integral a => (a, a) -> a 
divide_v1 (m, n) = (m + n) `div` 2 

我调用函数有一对积分 值,它按预期工作:

divide_v1 (1, 3) 

大。如果我的数字总是积分,那就完美了。

这里是一个函数,一对分数 值和将其划分:

divide_v2 :: Fractional a => (a, a) -> a 
divide_v2 (m, n) = (m + n)/2 

我调用函数有一对分数 值,它按预期工作:

divide_v2 (1.0, 3.0) 

太好了。如果我的数字总是Fractionals,那就完美了。

我想的作品无论 号是否是积分还是小数形式的函数:

divide_v3 :: Num a => (a, a) -> a 
divide_v3 (m, n) = (m + n) ___ 2 

应怎样使用运营商_

+3

请注意,'div'和'/'做_genuinely different_的事情,这就是为什么他们有不同的名称。没有办法实现'/'并且保持Integral数据类型,除非你想要一个错误的世界。哈斯克尔通过在写作之前让你思考并决定你真正想要的东西来做正确的想法。我认为你应该能够决定你是否想要Int,Integer,Rational,Double或其他。如果你试图做一些通用的事情,重新考虑是否真的可以一般地对待分工。 – AndrewC

回答

4

为了扩大AndrewC的说法,div没有与/的相同属性。例如,在数学中,如果除以b = c,则c次b == a。使用Double和Float等类型时,操作符/和*会满足此属性(只要该类型的准确性允许)。但是当与Ints一起使用div时,该属性不适用。 5 div 3 = 1,但1 * 3/= 5!所以如果你想对各种数字类型使用相同的“除法操作”,你需要考虑你想如何表现。另外,你几乎肯定不会想要使用相同的运算符/,因为这会引起误解。

如果你希望你的“除法运算”返回相同类型作为其操作数,这里要完成的一个方法:

class Divideable a where 
    mydiv :: a -> a -> a 

instance Divideable Int where 
    mydiv = div 

instance Divideable Double where 
    mydiv = (/) 

在GHCI,它看起来像这样:

λ> 5 `mydiv` 3 :: Int 
1 
λ> 5 `mydiv` 3 :: Double 
1.6666666666666667 
λ> 5.0 `mydiv` 3.0 :: Double 
1.6666666666666667 

另一方面,如果你想做“真正”的划分,你需要像这样转换积分类型:

class Divideable2 a where 
    mydiv2 :: a -> a -> Double 

instance Divideable2 Int where 
    mydiv2 a b = fromIntegral a/fromIntegral b 

instance Divideable2 Double where 
    mydiv2 = (/) 

在GHCI,这给:

λ> 5 `mydiv2` 3 
1.6666666666666667 
λ> 5.0 `mydiv2` 3.0 
1.6666666666666667 
1

我认为你正在寻找相关类型,它允许隐式类型转换,并很好地解释here。以下是添加双精度和整数的例子。

class Add a b where 
    type SumTy a b 
    add :: a -> b -> SumTy a b 

instance Add Integer Double where 
    type SumTy Integer Double = Double 
    add x y = fromIntegral x + y 

instance Add Double Integer where 
    type SumTy Double Integer = Double 
    add x y = x + fromIntegral y 

instance (Num a) => Add a a where 
    type SumTy a a = a 
    add x y = x + y