我有以下代码,基于此公式实现反函数计算:
derivation :: (Fractional a) => (a -> a) -> (a -> a)
derivation f = \ x -> ( ( f (x + dx) - f (x) ) / dx ) where dx = 0.1
evalA k f
| k == 0 = \x -> x
| otherwise = \x -> (derivation (evalA (k-1) f) x) / (derivation f x)
inverseFun f x =
let
x0 = 3.0
eps = 0.001
iter k prev sum =
let
elemA = evalA k f x0
elemB = prev * (x - (f x0)) / (if k == 0 then 1 else k)
newItem = elemA * elemB
in
if abs (newItem) < eps
then sum
else iter (k + 1) elemB (sum + newItem)
in
iter 0 1.0 0.0
f1 = \x -> 1.0 * x * x
main = do
print $ inverseFun f1 2.5
我需要通过将 evalA
移动到 inverseFun
内来优化它,并存储上一步计算 A'n/F' 以在下一次迭代中重用它,如果可能的话。。据我了解,每次 evalA
返回某种函数,然后 x 应用,就在声明 elemA
之前。
如何转换我的 evalA
或重写它以存储以前的结果(显然,通过将这些结果传递到 iter
中)?
如果计算不太精确,请不要介意,它需要良好的 x0
和 eps
选择。我的主要问题是 lambda 转换。
最佳答案
如果您更改 inverseFun
的定义,使得 (if k == 0 then 1 else k)
改为 fromIntegral (if k == 0然后 1::Int else k)
,然后您可以为所有函数提供类型签名:
derivation :: (Fractional a) => (a -> a) -> a -> a
evalA :: (Fractional a) => Int -> (a -> a) -> a -> a
inverseFun :: (Fractional a, Ord a) => (a -> a) -> a -> a
f1 :: (Fractional a) => a -> a
这肯定有帮助。
这对于我解决您的问题实际上很重要,因为我们需要 k
为 Int
,而您已将其用作 Fractional a => 一个
。 fromIntegral
修复了这个问题,但它需要知道它是一个 Int
,所以我只是添加了内联类型签名来帮助编译器。
由于您的函数仅依赖于先前的单个值,因此您可以使用 Prelude
中我们方便的 friend ,iterate::(a -> a) -> a -> [a]
。这会一遍又一遍地应用一个函数,产生无限的值列表。然后我们可以在任何点对其进行索引以获得所需的结果(这就是为什么拥有 k
一个 Int
很重要!)。
我们的函数看起来像
evalA :: Fractional a => Int -> (a -> a) -> a -> a
evalA k f = iterate go id !! k
where
go = ???
这里 id
与 \x -> x
的基本情况相同,只是更短并且具有更多优化规则。它用作生成此列表的初始值。为了实现实际的计算 go,我们需要它接受之前的结果作为参数:
where
go prev = \x -> derivation prev x / derivation f x
但是 hlint
认为这是“糟糕的风格”,因此建议将其转换为以下形式
where
go prev x = derivation prev x / derivation f x
就是这样!我对其进行了测试,并得到了与您的示例输入完全相同的结果。完整代码可查看here .
关于haskell - 无法正确理解 Haskell 中的 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26221606/