Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/37.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell Can';我不能正确理解哈斯克尔的兰博达斯_Haskell_Lambda_Calculus - Fatal编程技术网

Haskell Can';我不能正确理解哈斯克尔的兰博达斯

Haskell Can';我不能正确理解哈斯克尔的兰博达斯,haskell,lambda,calculus,Haskell,Lambda,Calculus,我有以下代码,基于以下公式实现反函数计算: 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 :: (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

派生::(分数a)=>(a->a)->(a->a)
导数f=\x->((f(x+dx)-f(x))/dx),其中dx=0.1
埃瓦拉k f
|k==0=\x->x
|否则=\x->(派生(evalA(k-1)f)x)/(派生f x)
反f x=
让
x0=3.0
每股收益=0.001
国际热核实验堆k上和=
让
elemA=evalA k f x0
elemB=prev*(x-(f x0))/(如果k==0,则为1,否则为k)
newItem=elemA*elemB
在里面
如果abs(新项目)1.0*x*x
main=do
打印$inverseFun f1 2.5
我需要通过在
inverseFun
中移动
evalA
来优化它,并存储上一步计算A'n/F',以便在下一次迭代中重用它(如果可能的话)。据我所知,每次
evalA
都返回某种函数,x在声明
elemA
之前应用

我如何转换我的
evalA
或重写它以存储以前的结果(显然,通过将这些结果传递到
iter


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

如果更改
inverseFun
的定义,使
(如果k==0,则1 else k)
改为
from integral(如果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
,而您已经将其用作
分数a=>a
。来自integral的
修复了这个问题,但是它需要知道它是
Int
,所以我只是添加了内联类型签名来帮助编译器

由于您的函数只依赖于前面的单个值,因此您可以使用我们方便的朋友从
Prelude
iterate::(a->a)->a->[a]
。这会一次又一次地应用函数,产生一个无限的值列表。然后,我们可以在任意点对其进行索引以获得所需的结果(这就是为什么拥有
k
a
Int
非常重要的原因!)

我们的函数看起来像

evalA :: Fractional a => Int -> (a -> a) -> a -> a
evalA k f = iterate go id !! k
    where
        go = ???
这里的
id
与您的基本情况
\x->x
相同,只是更短,并且有更多的优化规则。它用作生成此列表的初始值。要实现实际计算,我们需要它接受前面的结果作为参数:

    where
        go prev = \x -> derivation prev x / derivation f x
但是
hlint
认为这是“糟糕的风格”,因此建议将其转换为表单

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

就这样!我对它进行了测试,得到了与您的示例输入完全相同的结果。可以查看完整的代码。

可以使用
求导函数而不是
求导函数来获得函数的精确导数。谢谢@bheklir的详细解释。我必须自己实现求导计算