我使用Taylor Series实现了sin
函数。在其中我正在使用map
:
sin' x = sum $ map (\n -> term x n) [0..50]
where term x n = (x^pw / fromIntegral (fact pw))*(-1)^n
pw = 2*n+1
但是如何在Writer的日志中“保存”中间值(使用tell
)?我是否必须使用递归调用重写我的函数?我无法理解如何在没有递归的情况下获得这些中间值
答案 0 :(得分:1)
我不确定这是你要求的,但这是我能想到的唯一有用的Writer
方法。
这种天真的泰勒系列实现的问题在于你一遍又一遍地计算功率和阶乘,实际上逐步增加它会更有效率。复发是这样的:
term' x pw ≡ - x^2 * term' x (pw-2) / fromIntegral pw
当然,您不希望为每个加数重新计算,而是想要随时对术语求和。那是作家进来的地方;我们当然需要Writer (Sum Double)
。
procTerms :: Double -> Int -> Writer (Sum Double) Double
procTerms x 1 = tell (Sum x) >> return x
procTerms x pw = do
newterm <- fmap (* (- x^2 / fromIntegral pw)) $ term' x (pw-2)
tell $ Sum newterm
return newterm
我们不能真正摆脱这里的递归;使用mfix
的修复点没有用,因为我们无法从结果中获取反向引用。