制胜战略是定义递归函数在延续传递风格被memoized:
let gcd_cont k (a,b) =
let (q, r) = (a/b, a mod b) in
if r = 0 then b else k (b,r)
定义递归gcd_cont
功能相反,我们增加一个说法,“延续”是代之以递归。现在我们定义两个高阶函数,call
和memo
,它们对具有延续参数的函数进行操作。第一个功能,call
被定义为:
let call f =
let rec g x =
f g x
in
g
它建立一个功能g
这没有什么特别之处,但呼吁f
。第二个功能memo
构建一个功能g
实现记忆化:
let memo f =
let table = ref [] in
let compute k x =
let y = f k x in
table := (x,y) :: !table; y
in
let rec g x =
try List.assoc x !table
with Not_found -> compute g x
in
g
这些函数具有下列签名。
val call : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b = <fun>
val memo : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b = <fun>
现在我们定义gcd
函数的两个版本,第一个没有记忆化,第二个与记忆化:
let gcd_call a b =
call gcd_cont (a,b)
let gcd_memo a b =
memo gcd_cont (a,b)
此答案如何提高MichaelGrünewald的回答? – 2014-09-11 16:13:37
@AdèleBlanc-Sec指出了“真实世界ocaml”一书的正式解释。它真的详细解释了'备忘录'是如何工作的。老实说,迈克尔的回答中的“延续传球风格”有点复杂或者误导,如果人们不能真正理解什么是“延续传球” – 2014-09-12 10:22:45