加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

优化 – 在F#/ Scala中优化相互递归的标准方法是什么?

发布时间:2020-12-16 09:02:04 所属栏目:安全 来源:网络整理
导读:这些语言不支持“原生”的相互递归函数优化,所以我猜它必须是蹦床或者……嘿……重写为循环)我想念一些东西吗? 更新:似乎我对FSharp撒了谎,但我只是没有看到谷歌搜索时相互尾调用的例子 解决方法 首先,F#本身支持相互递归的函数,因为它可以受益于.NET IL(
这些语言不支持“原生”的相互递归函数优化,所以我猜它必须是蹦床或者……嘿……重写为循环)我想念一些东西吗?

更新:似乎我对FSharp撒了谎,但我只是没有看到谷歌搜索时相互尾调用的例子

解决方法

首先,F#本身支持相互递归的函数,因为它可以受益于.NET IL( MSDN)中提供的tailcall指令.但是,这有点棘手,可能不适用于.NET的某些替代实现(例如Compact Frameworks),因此您有时可能需要手动处理.

一般来说,我有几种方法可以解决它:

> Trampoline – 当递归深度太高时抛出异常并实现处理异常的顶级循环(异常将携带信息以恢复调用).您也可以简单地返回一个值,指定应该再次调用该函数,而不是异常.
>使用计时器展开 – 当递归深度太高时,您创建一个计时器并给它一个回调,该回调将在很短的时间后由计时器调用(计时器将继续递归,但使用的堆栈将被丢弃) .

使用存储需要完成的工作的全局堆栈可以完成同样的事情.您可以向堆栈添加函数,而不是计划计时器.在顶层,程序将从堆栈中选择函数并运行它们.

为了给出第一种技术的具体例子,在F#中你可以这样写:

type Result<′T> =
  | Done of ′T
  | Call of (unit -> ′T)

let rec factorial acc n = 
  if n = 0 then Done acc
  else Call(fun () -> factorial (acc * n) (n + 1))

这也可以用于相互递归的函数.命令循环将简单地调用存储在Call(f)中的f函数,直到它产生Done并得到最终结果.我认为这可能是实现这一目标的最简洁方法.

我确信还有其他复杂的技术来处理这个问题,但那些是我所知道的(我用过的).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读