gpt4 book ai didi

haskell - 在 Haskell 中为 Numeric 类划分

转载 作者:行者123 更新时间:2023-12-01 02:01:47 25 4
gpt4 key购买 nike

我正在尝试定义一个函数 toVal :: (Num a) => (Fraction a) -> a .该函数取一个分数并计算其数值。但由于该函数使用除法,我可以执行以下操作,因为除法是由 Num a 的子类上的不同函数定义的。 :

data Fraction a = Constant a
|Rational{numerator :: (Fraction a), denominator :: (Fraction a)}


toVal1 :: (Integral a) => (Fraction a) -> a
toVal1 (Constant a) = a
toVal1 (Rational num den) = (toVal1 num) `div` (toVal1 den)

toVal2 :: (Fractional a) => (Fraction a) -> a
toVal2 (Constant a) = a
toVal2 (Rational num den) = (toVal2 num) / (toVal2 den)

有没有办法可以组合这两个函数,以便我可以拥有一个通用函数 toVal :: (Num a) => (Fraction a) -> a ?

最佳答案

不,因为 Num没有除法的概念,或者用 C++ 术语来说,因为没有 dynamic_cast<...>在 haskell 。

您可以引入自己的类型类:

class HasDivOp a where
divOp :: a -> a -> a

instance HasDivOp Int where divOp = div
instance HasDivOp Integer where divOp = div
instance HasDivOp Double where divOp = (/)
instance HasDivOp Float where divOp = (/)

然后有一个函数来获取正确的 divOp :
toVal :: (Num a, HasDivOp a) => (Fraction a) -> a
toVal (Constant a) = a
toVal (Rational a b) = toVal a `divOp` toVal b

减少代码重复的另一种方法是添加一个附加函数:
divG :: (a -> b) -> (a -> a -> b) -> Fraction a -> b
divG p _ (Constant x) = p x
divG p f (Rational num den) = f (divG p f num) (divF p f den)

也就是说,对于固定 a s 和 b告诉 divF如何结合两个 a s 成 b ,或如何转换 ab ,可以减少两个 Fraction a s 成单 b .在您的所有情况下 a = b ,所以我们可以定义另一个助手:
divF :: (a -> a -> a) -> Fraction a -> a
divF = divG id

现在我们可以同时定义 toVal1toVal2divF 方面:
toVal1 :: Integral n => Fraction n -> Fraction n -> n
toVal1 = divF div

toVal2 :: Fractional n => Fraction n -> Fraction n -> n
toVal2 = divF (/)

话虽如此,两者 toValtoVal1导致整数上的有趣行为:
toVal1 (Rational (Rational 2 3) (Rational 2 3)) = 0 :: Int

但是 x div对于任何 x /= 0,x 都应该是 1 .如果您对积分进行预处理 Fraction不会出现这个问题:
rationalDiv :: Integral n => Fraction a -> Fraction a -> Fraction a
rationalDiv (Constant a ) (Constant c ) = Rational a c
rationalDiv (Constant a ) (Rational c d) = Rational (a * d) c
rationalDiv (Rational a b) (Constant c ) = Rational a (b * c)
rationalDiv (Rational a b) (Rational c d) = Rational (a * d) (b * c)

请注意,这需要一个 Num Fraction 的实例由于 * .这样你就可以最大程度地控制实际的划分,只需要在最后转换元素:
toVal3 :: Integral n => Fraction n -> n
toVal3 = divF div . divF rationalDiv

这正确导致 1在我们上面的例子中。但回到主题:不,你不能只使用 Num作为约束,您需要使用另一个实际上具有除法概念的约束。

关于haskell - 在 Haskell 中为 Numeric 类划分,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35741030/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com