我有一个与Scott's Railway Oriented Programming中使用的Result
类型相似的歧视联盟。为简单起见,这里稍作简化:
type ErrorMessage = ErrorMessage of string
type ValidationResult<'a> =
| Success of 'a
| Error of ErrorMessage
我有一个相应的模块ValidationResult
,其中包含作用于这些ValidationResult
的函数,其中一个是递归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
但它不是尾递归的,我想把它转换成它。我怎么能这样做?
答案 0 :(得分:2)
只需删除对doubleMap
的调用即可:
let rec retryable errorHandler f =
match f() with
| Success x -> x
| Error e ->
errorHandler e
retryable errorHandler f
答案 1 :(得分:2)
F#编译器以两种不同的方式编译尾递归函数。
.tail
IL指令进行尾调用。这也是一个尾调用,但由.NET运行时处理,而不是由F#编译器消除。在您的情况下,retryable
函数 已经是尾递归,但它是第二种。丹尼尔的回答使其变得简单,使其成为第一种。
但是,您可以保留该功能,它将是尾递归的。唯一需要注意的是,编译器默认情况下不会在调试模式下生成.tail
指令(因为它会混乱调用堆栈),因此您需要显式启用它(在项目选项中,选中“生成尾部”)调用“)。