haskell - 为什么我的子函数调用次数呈指数级增长?
问题描述
我对以下 Haskell 函数有疑问:
evalPol :: Float
-> Float
-> Integer
-> Integer
-> (s -> a -> [(s, [(Float, Float)])])
-> (s -> a)
-> [s]
-> [((s -> Float), Float)]
-> [((s -> Float), Float)]
evalPol eps gamma maxIter nIter gen pol ss vofss =
if nIter >= maxIter || delta < eps
then reverse ((vofs', delta) : vofss)
else evalPol eps gamma maxIter (nIter + 1) gen pol ss ((vofs', delta) : vofss)
where delta = maximum [abs (vofs s - vofs' s) | s <- ss]
vofs' s = actVal gamma gen vofs s (pol s)
vofs = (fst . P.head) vofss
如果我使用分析调用此函数maxIter = 1
并运行分析,那么我会看到函数条目计数,这对我来说很有意义:
evalPol..............2
evalPol.delta......1
evalPol.vofs'..441
上面的函数条目计数对我来说很有意义,如下所示:
evalPol
输入两次:- 一次,当从外面打电话时,和
- 一次,递归。(只允许一次递归调用,原因是:
maxIter = 1
.)
evalPol.delta
只调用一次,因为当evalPol
第二次(递归)调用时 test:nIter >= maxIter
成功,并且不需要评估delta
.我得到 441 个条目是有道理的
evalPol.vofs'
,因为我将该函数映射到列表中ss
,并且该列表中有 441 个项目。
现在,如果我只进行一项更改:调用evalPol
with maxIter = 2
,我发现我的程序不会在合理的时间内终止。让它在中断之前运行几个小时,我得到以下信息:
evalPol................2
evalPol.delta........2
evalPol.vofs'..60366
将条目数evalPol.delta
从 1 更改为 2(参见上面的 #2。)对我来说很有意义,因为我已经设置了maxIter = 2
. 但是,我没想到evalPol.vofs'
. (我期待看到 882 个条目,每个允许的递归有441个。)看起来条目evalPol.vofs'
数在. (我不知道,因为我没有让程序完成。)maxIter
如果我“展开”这 2 个递归案例,寻找对 的指数依赖maxIter
,我得到:
-- This is how I call it from outside:
evalPol eps gamma 2 0 gen pol ss [((const 0), 0)] = -- Assume delta >= eps and recurse.
evalPol eps gamma 2 1 gen pol ss [(vofs', delta), ((const 0), 0)]
-- Now, expand delta
delta = maximum $ map (abs . uncurry (-) . (vofs &&& vofs')) ss -- Substitute for vofs, vofs', and pol, using previous iteration's definitions.
= maximum $ map ( abs
. uncurry (-)
. ( vofs' &&&
\s -> actVal gamma gen vofs' s 0
)
) ss
= maximum $ map ( abs
. uncurry (-)
. ( \s -> actVal gamma gen (const 0) s 0 &&&
\s -> actVal gamma gen (\s' -> actVal gamma gen (const 0) s' 0) s 0
)
) ss
正如预期的那样,我看到递归正在发展,但我没有看到任何嵌套调用 into ,这可能解释了我观察到evalPol.vofs'
的(假设)指数依赖性。maxIter
此外,我已经查看了actVal
函数gen
和函数,并且没有evalPol.vofs'
隐藏在其中任何一个中的调用。evalPol.vofs'
因此,我无法解释我在maxIter = 2
此案中观察到的大量条目。
解决方案
我通过使用vofs'
函数的向量表示来解决这个问题。这样做消除了之前执行的冗余计算。vofs'
对于2 次递归情况,我现在看到 882 次调用 , 的新等效项,这是我所期望的。也就是说,我希望 的执行时间evalPol
是线性的,maxIter
并且使用 的向量表示vofs'
,这就是我所看到的。
推荐阅读
- r - 安装 R 包“ld:警告:找不到选项的目录”时出现问题
- .net-core - VS 2019 C# 控制台 netcore 3 应用程序未调试
- google-cloud-platform - 使所有域的名称服务器回复相同
- excel - 如果文件夹名称相同,则替换文件夹
- ruby-on-rails - 音频不适用于heroku上的rails应用程序
- sql - SQL 可行性:可以按值挤出行并以自定义方式组合表吗?
- javascript - 在输入中格式化数字(掩码)
- python - 在 Python 中从字符串中去除非字母字符的代码
- flutter - 如何重建提供者选择器但不重建它们的孩子
- jenkins - 依赖于 Jenkins 构建布尔参数的表达式在管道中不起作用