【发布时间】:2016-05-03 13:19:16
【问题描述】:
我有一个与Scott's Railway Oriented Programming 中使用的Result 类型类似的可区分联合。为简单起见,这里稍微简化一下:
type ErrorMessage = ErrorMessage of string
type ValidationResult<'a> =
| Success of 'a
| Error of ErrorMessage
我有一个相应的模块ValidationResult,其中包含作用于这些ValidationResults 的函数,其中一个是递归retryable 函数,它允许再次调用参数f: unit -> 'a(例如读取来自stdin) 如果ValidationResult 是Error:
module ValidationResult
let doubleMap success error = function
| Success x -> success x
| Error e -> error e
let rec retryable errorHandler f =
let result = f ()
let retry e =
errorHandler e
retryable errorHandler f
doubleMap id retry result
但它不是尾递归的,我想将其转换为尾递归。我该怎么做?
【问题讨论】:
-
AFAIK,函数本身是尾递归的,但编译器不会将其编译成循环,因为它使用嵌套函数 - 所以您需要在项目选项中启用“尾调用” - 这样,它将生成带有实际尾调用指令的 .NET 代码。
-
但如果你在 Windows 或 .NET Core 上运行,JIT 甚至不需要实际的尾调用指令,它无论如何都会优化尾调用。
-
@TomasPetricek 我想如果我将我的代码反编译成 C# 并看到一个
while (true)循环,这意味着我的代码是尾递归的,这在我的doubleMap版本中不会发生 -
@rexcfnghk 我在答案中添加了更多细节。
标签: recursion f# tail-recursion