我最近一直在学习Haskell,正在和一位正在通过SICP工作的朋友交谈。我们很想比较Common Lisp和Scheme,所以我决定尝试将练习1.29翻译成Haskell。
本练习使用函数sigma,它表示数学求和函数Sigma。此函数采用函数f应用于每个术语,下限,应用于每个术语以获得下一个术语的函数和上限。它返回应用于每个术语的f的总和。
simpsonIntegral应该使用Simpson规则使用“精度”n来近似函数f在[a,b]范围内的积分。我无法使这个功能起作用,因为似乎有些东西我不了解所涉及的类型。
这段代码将使用ghc的6.12.1版进行编译,但是simpsonIntegral将被赋予一个类型上下文(Integral a,Fractional a),它没有任何意义,只要你调用它就会爆炸。我有一点工作,但我所做的显然是一个黑客,我想在这里询问如何处理这个问题。
如何习惯性地处理积分 - > h需要分数/实数转换?我读了很多东西,但似乎没有什么是显而易见的。
sigma :: (Ord a, Num b) => (a -> b) -> a -> (a -> a) -> a -> b
sigma f a next b = iter a 0
where
iter current acc | current > b = acc
| otherwise = iter (next current) (acc + f current)
simpsonIntegral f a b n = 1.0 * (h / 3) * (sigma simTerm 0 (1+) n)
where
h = (b - a) / n
simTerm k = (yk k) * term
where
yk k = f (a + h * k)
term =
case k of
0 -> 1
1 -> 1
otherwise -> if odd k then 4 else 2
答案 0 :(得分:6)
fromIntegral :: (Integral a, Num b) => a -> b
r = fromIntegral i
答案 1 :(得分:3)
跟进Justice的回答:如果您对fromIntegral
的放置位置感到好奇,请编译以下内容:
simpsonIntegral :: (Integral a, Fractional b) => (b -> b) -> a -> a -> a -> b
simpsonIntegral f a b n = 1.0 * (h / 3) * (sigma simTerm 0 (1+) n)
where
h = fromIntegral (b - a) / fromIntegral n
simTerm k = (yk k) * term
where
yk k = f (fromIntegral a + h * fromIntegral k)
term =
case k of
0 -> 1
1 -> 1
otherwise -> if odd k then 4 else 2
似乎有效:
*Main> simpsonIntegral (^3) 0 1 100
0.2533333233333334
*Main> simpsonIntegral (^3) 0 1 1000
0.2503333333323334
答案 2 :(得分:1)
问题是函数“odd”期望它的参数是Integral类型。编译器然后推断您的变量“k”是Integral类型。但是通过使用操作“/”,编译器推断“k”也是Fractional类型。解决方案可以简单到将“k”转换为真正需要的整数:
if odd (round k) then 4 else 2
如果您想了解有关Haskell中数字转换的更多信息,请查看Converting_numbers
作为旁注,这是编写西格玛函数的另一种方法:
sigma f a next b = sum $ map f $ takeWhile (<= b) $ iterate next a