6
我正在努力理解與CPS的折返。 這一次我能理解:F#延續傳遞折返
let listFoldBack combine acc l =
let rec Loop l cont =
match l with
| h :: t -> Loop t (fun racc -> cont (combine h racc))
| [] -> cont acc
Loop l id
listFoldBack (fun x a -> (2*x::a)) [] [1;2;3]
// call sequence
[1;2;3] id
Loop [2;3] (fun a -> (combine 1 a))
Loop [3] (fun a -> (combine 1 (combine 2 a)))
Loop [] (fun a -> (combine 1 (combine 2 (combine 3 a))))
(fun a -> (combine 1 (combine 2 (combine 3 a)))) []
2::(4::(6::[]))
但後來:
let fib n =
let rec fibc a cont =
if a <= 2 then cont 1
else
fibc (a - 2) (fun x -> fibc (a - 1) (fun y -> cont(x + y)))
fibc n id
// call sequence
fibc (4) id
fibc (2) (fun x -> fibc (3) (fun y -> id(x + y)))
(fun x -> fibc (3) (fun y -> id(x + y))) (1)
fibc (3) (fun y -> id(1 + y))
fibc (1) (fun x -> fibc (2) (fun y -> (fun z -> id(1+z)) (x + y)))
fibc (2) (fun y -> (fun z -> id(1+z))(1 + y)))
(fun y -> (fun z -> id(1+z))(1 + y))) (1)
fun z -> id(1+z)(1+1)
id (1+2)
3
很難跟上。
更糟糕的是:
type Tree<'a> =
| Leaf
| Node of 'a * Tree<'a> * Tree<'a>
let node x l r = Node(x,l,r)
let treeFoldBack f leaf tree =
let rec loop t cont =
match t with
| Leaf -> cont leaf
| Node(x,l,r) -> loop l (fun lacc ->
loop r (fun racc -> cont(f x lacc racc)))
loop tree id
let tree1 =
(node 4
(node 2
(node 1 Leaf Leaf)
(node 3 Leaf Leaf))
(node 6
(node 5 Leaf Leaf)
(node 7 Leaf Leaf)))
// call sequence by means of text replacing
... a lot of steps, lines too long to fit
cont(f 4 (f 2 (f 1 Leaf Leaf) (f 3 Leaf Leaf))
(f 6 (f 5 Leaf Leaf) (f 7 Leaf Leaf))))
結果是正確的,但很難跟上。 對於所有的情況下,模式是這樣的:
loop l (fun lacc -> loop r (fun racc -> cont(f x lacc racc)))
calculate loop l, result goes in lacc.
calculate loop r, result goes in racc.
calculate f x lacc racc and result is argument for cont.
爲什麼這項工作?如何理解這一點?