使用“area”时没有(Fractional Int)的实例

时间:2015-05-05 20:50:54

标签: haskell recursion types casting functional-programming

我是Haskell的新手,我正在编写一个计算函数极限的程序。因此,给定了两个列表ab,一个delta dx = 0.001,以及集成lr的限制,我想递归计算下面的区域曲线与方程: a1(x)^b1 + a2(x)^b2 + ... + an(x)bn其中xlr之间的所有值,每个值之间的增量为dx。我想技术部分并不重要,但它有助于阅读代码:

import Text.Printf (printf)

-- This function should return a list [area].
solve :: Int -> Int -> [Int] -> [Int] -> [Double]
solve l r x y = [area l r x y]

area l r a b = if (l < r)
            then (calc l a b) * 0.001 + (area (l + 1) r a b)
            else (calc r a b) * 0.001


calc n (a:arest) (b:brest) = (fromIntegral(n) ^^ b) * fromIntegral(a) + (calc n arest brest)
calc n [] [] = 0


--Input/Output.
main :: IO ()

main = getContents >>= mapM_ (printf "%.1f\n"). (\[a, b, [l, r]] -> solve l r a b). map (map read. words). lines

上述代码没有错误,但只要我将area (l + 1) r a b更改为area (l + 0.001) r a b,我就会收到以下错误消息:

No instance for (Fractional Int) arising from a use of `area'

我尝试创建一个新类并且是一个抽象类型但是没有用,还有其他任何想法吗?

1 个答案:

答案 0 :(得分:7)

问题是Int不是Fractional类型。换句话说,它没有名为0.001 [注1] 的值,但是您已经请求Haskell在您的代码中为您提供这样的值。

您正在发出此请求,因为0.001被另一个参数(在本例中为(+))提供给l函数,该参数类型为Int。这是一个问题,因为该函数具有类型(+) :: (Num a) => a -> a -> a:换句话说,有许多不同的函数(+)都具有类型a -> a -> a; a类型类中的每个类型Num都存在其中一个函数。

由于我们知道该函数的一个参数是Int,因此我们使用特定函数(+) :: Int -> Int -> Int。这就是l + 0.001变得奇怪的原因。

至于解决问题:您可能希望lr属于Double类型(他们可以在数字所在的左右边界?)但如果你确定它们必须是Int,那么你可能想写fromIntegral l + 0.001

关于样式的旁注:Haskell中的括号始终只是分组/优先级,函数优先于比特殊形式(letcaseif更高优先级的运算符, do),函数应用程序总是左关联的,或者&#34;贪婪的名词&#34;:一个函数吃掉它前面的任何东西。你写的:

(fromIntegral(n) ^^ b) * fromIntegral(a) + (calc n arest brest)

可能写得更好:

fromIntegral a * fromIntegral n ^^ b + calc n arest brest

calc周围的括号不是必需的(因为像+这样的运算符的优先级低于函数应用程序),na周围的括号也不是必需的(因为这些子表达式是不可分割的块; fromIntegral(n)fromIntegral (n)相同,与fromIntegral n相同。

  1. 正如@dfeuer在下面提到的:秘密地,当你写0.001时,它没有明确的类型;相反,它在内部被翻译为fromRational 0.001,其中后者0.001是明确类型Rational的确定值,就像你写4时它被翻译为{{ 1}}其中后者4是确定类型fromInteger 4的确定值。问题实际上是Integer没有fromRational函数,因为Int不是定义Int的{​​{1}}类型类的一部分。并且它不属于该类型类的一部分,因为语言设计者更喜欢将一个错误归结为一个分数的无声舍入/丢弃。