我是Haskell的新手,我正在编写一个计算函数极限的程序。因此,给定了两个列表a
和b
,一个delta dx = 0.001
,以及集成l
和r
的限制,我想递归计算下面的区域曲线与方程:
a1(x)^b1 + a2(x)^b2 + ... + an(x)bn
其中x
是l
与r
之间的所有值,每个值之间的增量为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'
我尝试创建一个新类并且是一个抽象类型但是没有用,还有其他任何想法吗?
答案 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
变得奇怪的原因。
至于解决问题:您可能希望l
和r
属于Double
类型(他们可以在数字所在的左右边界?)但如果你确定它们必须是Int
,那么你可能想写fromIntegral l + 0.001
。
关于样式的旁注:Haskell中的括号始终只是分组/优先级,函数优先于比特殊形式(let
,case
,if
更高优先级的运算符, do
),函数应用程序总是左关联的,或者&#34;贪婪的名词&#34;:一个函数吃掉它前面的任何东西。你写的:
(fromIntegral(n) ^^ b) * fromIntegral(a) + (calc n arest brest)
可能写得更好:
fromIntegral a * fromIntegral n ^^ b + calc n arest brest
calc
周围的括号不是必需的(因为像+这样的运算符的优先级低于函数应用程序),n
和a
周围的括号也不是必需的(因为这些子表达式是不可分割的块; fromIntegral(n)
与fromIntegral (n)
相同,与fromIntegral n
相同。
0.001
时,它没有明确的类型;相反,它在内部被翻译为fromRational 0.001
,其中后者0.001
是明确类型Rational
的确定值,就像你写4
时它被翻译为{{ 1}}其中后者4是确定类型fromInteger 4
的确定值。问题实际上是Integer
没有fromRational
函数,因为Int
不是定义Int
的{{1}}类型类的一部分。并且它不属于该类型类的一部分,因为语言设计者更喜欢将一个错误归结为一个分数的无声舍入/丢弃。