无法正确理解Haskell中的lambdas

时间:2014-10-06 17:33:18

标签: haskell lambda calculus

我有以下代码,基于这个公式实现逆函数计算:

enter image description here

enter image description here

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)?

请注意,如果此计算不太精确,则需要选择良好的x0eps。我的主要问题是lambda转换。

1 个答案:

答案 0 :(得分:3)

如果您更改inverseFun的定义,使(if k == 0 then 1 else k)改为fromIntegral (if k == 0 then 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 => afromIntegral修复了这个问题,但需要知道它是Int,所以我只是添加了内联类型签名来帮助编译器。

由于您的功能仅取决于之前的单个值,因此您可以使用Prelude iterate :: (a -> a) -> a -> [a]中的方便朋友。这反复应用函数,产生无限的值列表。然后我们可以在任何时候对其进行索引以获得所需的结果(这就是为什么kInt很重要!)。

我们的功能看起来像

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

但这被认为是&#34;风格不佳&#34;按hlint,因此建议将其转换为

形式
    where
        go prev x = derivation prev x / derivation f x

那就是它!我测试了它,并为您的示例输入得到了完全相同的结果。可以查看完整代码here