Haskell浮点数计算错误

Haskell float calculation error

我正在尝试编写一个计算曲线下面积的简短函数,但我一直收到类型不匹配错误。

以下函数中的参数:lr为求值范围,ab为曲线参数。

solve :: Int -> Int -> [Int] -> [Int] -> [Double]
solve l r a b = [area]
    where eval a b p = fromIntegral . sum . map (\(ai, bi) -> ai * p ^ bi) $ zip a b
          area = foldl (\acc p -> acc + 0.001 * eval a b p) 0 range
          range = map (\a -> (fromIntegral a :: Double ) / 1000) [l*1000..r*1000]

我感到非常沮丧,因为 Haskell 中的类型系统真的不是那么直观。有人可以建议在数值计算中处理浮点数时的最佳做法吗?


综上所述,上面的代码不起作用,因为:

如果我们想在不改变输入类型的情况下将这道题中的代数曲线计算为浮点值,我们可以将a转换为[Double]。这是代码:

solve :: Int -> Int -> [Int] -> [Int] -> [Double]
solve l r a b = [area]
    where eval p = sum . map (\(ai, bi) -> ai * p ^^ bi) $ zip af b
          area = foldl (\acc p -> acc + 0.001 * eval p) 0 range
          range = map (\x -> (fromIntegral x :: Double ) / 1000) [l*1000..r*1000]
          af = map fromIntegral a :: [Double]

我还将 ^ 更改为 ^^ 以处理负指数。

要了解类型错误,您应该了解一些类型 :)。一个好的起点是注释掉类型声明以查看 GHCi 推断的内容(在这种情况下,我们的错误不会改变,但确保我们的类型声明不是问题是一个很好的通用做法)。无论如何,当我们这样做时,我们遇到错误:

 floatingError.hs:4:47: error:
    • No instance for (Integral Double) arising from a use of ‘eval’
    • In the second argument of ‘(*)’, namely ‘eval a b p’
      In the second argument of ‘(+)’, namely ‘0.001 * eval a b p’
      In the expression: acc + 0.001 * eval a b p

我们从相关数字运算符 (*)(+) 的类型签名中得知它们接受相同类型的参数。这是我们错误的原因; eval 应该是整型。但是,我们对其应用了 fromIntegral 函数。因此,如果我们删除它,我们的函数应用程序会进行类型检查并且我们的程序会编译。

接下来,我们可以检查 GHCi 为 solve 推断出的类型签名:

solve :: (Integral b, Integral t) =>
 t -> t -> [Double] -> [b] -> [Double]

因为 Int 有一个类型类 Integral 的实例,我们知道我们声明的签名不会与我们修改的函数定义冲突。


我们的最终代码:

solve :: Int -> Int -> [Double] -> [Int] -> [Double]
solve l r a b = [area]
  where eval a b p = sum . map (\(ai, bi) -> ai * p ^ bi) $ zip a b
        area = foldl (\acc p -> acc + 0.001 * eval a b p) 0 range
        range = map (\a -> (fromIntegral a :: Double ) / 1000) [l*1000..r*1000]