2010-07-24 58 views
1

我有一个函数(在汤普森的函数函数编程的练习10.11),它计算函数在域(a,b)上的定积分值的近似值。它可能不是最优雅的功能,但我还是一个初学者:等效表达式在函数中产生不同的结果?

import Data.Ratio (Rational, (%), denominator, numerator) 
type R = Rational 

integrate :: (R -> R) -> R -> (R, R) -> R  
integrate f d (a, b) = foldr (+) 0 $ zipWith (*) (map f [a, a + d..b]) (widths d) 
where widths :: R -> [R] 
     widths = \n -> n : widths n 

eval :: R -> Double  
eval = \r -> (/) (fromIntegral $ numerator r) (fromIntegral $ denominator r) 

例如,

eval $ integrate (\x -> 20 + x^2) (1%10000) (-3%1, 3%1) = 
~> 138.00290001 

现在,widths d应相当于表达[d..]。但是,如果我用集成中的[d ..]替换宽度,我的函数会输出不正确的值。例如:

integrate' :: (R -> R) -> R -> (R, R) -> R  
integrate' f d (a, b) = foldr (+) 0 $ zipWith (*) (map f [a, a+d..b]) [d..] 

eval $ integrate' (\x -> 20 + x^2) (1%10000) (-3%1, 3%1) 
~> 41400870141.0029 

这是为什么?

+0

而不是“**编辑:**解决”,在这个网站上的礼仪,以纪念通过点击复选标记,正确的答案(在这种情况下,我的,因为它是唯一一个,你认为问题已解决)为“接受”。 – 2010-07-24 04:47:31

+0

你可以使用'repeat d'而不是'widths d'。 – sastanin 2010-07-24 11:55:52

回答

3

因为这两个陈述是不相同的。考虑当我打电话widths d会发生什么:

widths d = d : widths d 
     = d : d : widths d 
     ... 
     = [d, d, d, ...] 

换句话说,你得到的d秒的无限名单。但是,[d..]返回列表[d, d+1, d+2, ...]。要获得d s的无限列表,您可以编写[d,d..];一般而言,[d,d+n..]创建无限列表[d, d+n, d+2*n, ...]。更通俗的说,一般会写repeat d;重复有签名a -> [a],并无限重复其论证。

编辑:此外,一些风格等,点:function = \x -> ...是在所有情况下相同function x = ...。并且没有特别的理由用前缀/来编写你的eval函数;我会写它eval r = (fromIntegral $ numerator r)/(fromIntegral $ denominator r);但实际上,我只是使用fromRational :: Fractional a => Rational -> a函数而不是eval。您也可以用sum代替foldr (+) 0。并且您不需要创建d s的无限列表,然后繁殖所有内容;更简单地说,你可以只有sum . map (* d) $ map f [a, a + d..b]。当然,你可以再分发了这一点,并有

integrate'' :: (R -> R) -> R -> (R,R) -> R 
integrate'' f d (a,b) = d * (sum $ map f [a, a+d .. b])` 

然后我们有

> fromRational $ integrate'' (\x -> 20 + x^2) (1%10000) (-3%1, 3%1) 
138.00290001 
+0

谢谢。现在我觉得自己像个白痴。 – danportin 2010-07-24 04:41:44

+0

@danportin:检查工具hlint(风格建议和捕捉这些东西)和搜索引擎hoogle(用于查找具有特定类型签名的内置函数) – jberryman 2010-07-24 14:33:04

+0

感谢您提供的风格提示。我知道我可以用sum和lambda表达式在函数定义中用显式参数替换'foldr(+)0]'。不过,我刚刚了解到他们;所以我一直在使用它们。 但是,你说得对'map(* d)(map f [a,a + d..b'比我写的更干净更有效率,谢谢指出我不需要生成无限的宽度列表。 – danportin 2010-07-25 21:40:51

相关问题