【问题标题】:Overuse of fromIntegral in Haskell在 Haskell 中过度使用 fromIntegral
【发布时间】:2011-03-28 02:03:29
【问题描述】:

每当我使用双精度和整数编写函数时,我都会发现这个问题,即我经常不得不在函数中的任何地方使用“fromIntegral”。例如:

import Data.List

roundDouble
    :: Double
    -> Int 
    -> Double
roundDouble x acc = fromIntegral (round $ x * 10 ** fromIntegral acc) / 10 ** fromIntegral acc

有没有更简单的方法来写这个? (我知道可能有更简单的方法来四舍五入,如果有请告诉我!但我主要对如何避免使用这么多的“fromIntegrals”感兴趣。)

谢谢,阿什

【问题讨论】:

    标签: haskell integer double


    【解决方案1】:

    您可以使用^ 代替**^ 将任何 Integral 作为它的第二个参数,因此您不需要在第二个操作数上调用 fromIntegral。所以你的代码变成了:

    roundDouble x acc = fromIntegral (round $ x * 10 ^ acc) / 10 ^ acc

    其中只有一个fromIntegral。而你无法摆脱的那个 round 自然会返回一个 Integral 并且你不能对 Integral 执行非整数除法。

    【讨论】:

      【解决方案2】:

      我对编组代码也有类似的问题,其中fromIntegral 用于将CInt 转换为Int。我通常定义fI = fromIntegral 以使其更容易。您可能还需要给它一个明确的类型签名或使用 -XNoMonomorphismRestriction。

      如果您要进行大量数学运算,您可能需要查看Numeric Prelude,它似乎在不同数字类型之间具有更合理的关系。

      【讨论】:

      • 我期待看到定义 fI 的答案,所以我很高兴看到别人写它。我去看看 Numeric Prelude,它看起来很有用,谢谢!
      • 定义 fI 并不像其他一些答案那样巧妙,但与迄今为止的其他答案相比,它具有最广泛的适用性。
      【解决方案3】:

      有时我发现辅助函数很有用:

      roundDouble x acc = (round $ x * 10 ^ acc) /. (10 ^ acc)
          where 
          x /. y = fromIntegral x / fromIntegral y
      

      那个辅助函数也可以写成:

      (/.) = (/) `on` fromIntegral
      

      on 来自Data.Function

      【讨论】:

      • (/.) 的类型是 (Integral a, Fractional b, Integral a1) => a -> a1 -> b 而 (/) on fromIntegral 的类型是 (Fractional b , 积分 a) => a -> a -> b。如果你需要更通用的类型,on 是不合适的。
      【解决方案4】:

      另一个想法,类似于luqui's。我对fromIntegral 的大部分问题都与将Int 除以DoubleDouble 除以Int 的必要性有关。所以这个(/.) 允许划分任意两个Real 类型,不一定相同,不一定像luqui 的解决方案中的Integral 类型:

      (/.) :: (Real a, Real b, Fractional c) => a -> b -> c
      (/.) x y = fromRational $ (toRational x) / (toRational y)
      

      例子:

      ghci> let (a,b,c) = (2::Int, 3::Double, 5::Int)
      ghci> (b/.a, c/.a, a/.c)
      (1.5,2.5,0.4)
      

      它适用于任何两个Reals,但我怀疑合理的划分和与Rational的转换不是很有效。

      现在你的例子变成了:

      roundDouble :: Double -> Int -> Double
      roundDouble x acc = (round $ x * 10 ^ acc) /. (10 ^ acc)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-17
        相关资源
        最近更新 更多