代码之家  ›  专栏  ›  技术社区  ›  emi

等价表达式在函数中产生不同的结果?

  •  1
  • emi  · 技术社区  · 16 年前

    我有一个函数(汤普森的练习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..]

    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
    

    为什么会这样?

    1 回复  |  直到 16 年前
        1
  •  3
  •   Antal Spector-Zabusky    16 年前

    因为这两种说法并不相同。想想我打电话时会发生什么 widths d :

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

    换句话说,你会得到一个无限的 d s。然而, [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 函数而不是 . 您也可以替换 foldr (+) 0 sum . 你不需要创建一个无限的 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
    
    推荐文章