【发布时间】:2013-10-03 05:30:15
【问题描述】:
递归是一种强大的技术,因为它具有强大的可描述性。尾递归提供比普通递归更强大的计算,因为它将递归变为迭代。 Continuation-Passing Style (CPS) 可以将大量循环代码更改为尾递归。 Continuation Monad 提供递归语法,但本质上它是尾递归,也就是迭代。 100000阶乘应该合理使用Continuation Monad。这是代码。
type ContinuationBuilder() =
member b.Bind(x, f) = fun k -> x (fun x -> f x k)
member b.Return x = fun k -> k x
member b.ReturnFrom x = x
(*
type ContinuationBuilder =
class
new : unit -> ContinuationBuilder
member Bind : x:(('d -> 'e) -> 'f) * f:('d -> 'g -> 'e) -> ('g -> 'f)
member Return : x:'b -> (('b -> 'c) -> 'c)
member ReturnFrom : x:'a -> 'a
end
*)
let cont = ContinuationBuilder()
//val cont : ContinuationBuilder
let fac n =
let rec loop n =
cont {
match n with
| n when n = 0I -> return 1I
| _ -> let! x = fun f -> f n
let! y = loop (n - 1I)
return x * y
}
loop n (fun x -> x)
let x2 = fac 100000I
有错误消息:“由于 StackOverflowException 而终止进程。”
使用 ContinuationMonad 的 100000 阶乘有什么问题?
【问题讨论】:
-
“尾递归提供比普通递归更强大的计算,因为它将递归变为迭代。”这并不完全正确。如果递归太复杂而无法变成循环,则它只是将当前堆栈帧重新用于函数的下一次调用。
标签: f# monads tail-recursion continuations