制勝戰略是定義遞歸函數在延續傳遞風格被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