【发布时间】:2015-11-25 12:44:40
【问题描述】:
是否可以检查一个函数是否被声明为递归的,即使用 let rec?
我有一个 memoize 函数,但它不适用于任意递归函数。如果用户使用这样的函数调用它,我想给出一个错误。 (请随时告诉我这是否是处理 F# 错误的坏方法)
【问题讨论】:
-
什么是“任意递归函数”?你能给出一些你所问的代码示例吗?
标签: f#
是否可以检查一个函数是否被声明为递归的,即使用 let rec?
我有一个 memoize 函数,但它不适用于任意递归函数。如果用户使用这样的函数调用它,我想给出一个错误。 (请随时告诉我这是否是处理 F# 错误的坏方法)
【问题讨论】:
标签: f#
F# 代码编译为 .NET 通用中间语言。 F# rec 关键字只是对 F# 编译器的提示,它使正在定义的标识符在函数范围内可用。所以我相信没有办法在运行时发现函数被声明为递归的。
但是,您可以使用 System.Diagnostic.StackTrace 类 (https://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx) 在运行时获取和分析堆栈帧。但是访问堆栈信息会对性能产生重大影响(我假设您的记忆功能是为了加快程序性能)。由于编译器可以进行优化,因此程序的调试和发布版本中的堆栈信息也可能不同。
【讨论】:
我不认为它可以以一种明智和全面的方式来完成。
不过,您可能需要重新评估您的问题。我假设您的函数对递归函数“不起作用”,因为它只记录第一次调用,而所有递归调用都转到非记忆函数?根据您的情况,这可能不是一件坏事。
记忆化以记忆换取速度。在大型系统中,如果您只关心最终结果,您可能不想支付记忆中间结果的成本。所有这些字典都会随着时间的推移而增加。
但是,如果您特别关心递归函数的记忆,则可以以一种适合记忆的方式显式地构造它。见linkedthreads。
所以我的回答是 memoize 函数根本不应该关心递归。如果用户想要记忆一个递归函数,他必须理解所涉及的权衡,并以一种允许记忆中间调用的方式构造函数如果这是他需要的。
【讨论】: