bleis-tift
let f g =
printfn "f"
g 10
// fにとって、引数に渡す関数は"未来"のこと
f (fun x ->
printfn "%d" x
)
ret
と名前を付けます// 関数から戻りたい場合はretに値を渡す
// retに名前が付けられるの、Pythonのselfっぽさがある
let add1 x ret = ret (x + 1)
let mul2 x ret = ret (x * 2)
add1 10 (fun res ->
mul2 res (fun res ->
// (10 + 1) * 2
printfn "res=%d" res
)
)
// 普通の書き方
let add1Normal x = x + 1
// 継続渡しスタイル
let add1CPS x ret = ret (x + 1)
let f x = x + 1
let g x =
// これは末尾での関数呼び出し?
10 + f x
let h x =
use r = getResource ()
// これは末尾での関数呼び出し?
f x
let f x k = k (x + 1)
let g x k = f (x * 2) (fun res -> k res)
let h x k = g x (fun res -> k (res - 5))
h 10 (fun res -> res)
関数を呼び出さないもの:
引数 k
に結果を渡すだけ
// 通常版
let f x = x + 1
// CPS変換した版
let f x k = k (x + 1)
末尾位置で関数呼んでるもの:
呼び出し結果を引数 k
に渡すだけ
// 通常版
let g x = f (x * 2)
// CPS変換した版
let g x k = f (x * 2) (fun res -> k res)
// こっちでも可
let g x k = f (x * 2) k // kを消してもいい
末尾位置以外で呼んでるもの:
呼出結果を使って呼出後の計算を k
に渡す
// 通常版
let h x = g x - 5
// CPS変換した版
let h x k = g x (fun res -> k (res - 5))
let rec fact x =
match x with
| 0 -> 1
| n -> n * (fact (n - 1))
let rec fact x k = // kを追加
match x with
| 0 ->
// 関数を呼び出していない
1
| n -> n * (fact (n - 1))
let rec fact x k =
match x with
| 0 -> k 1 // kに結果を渡すように変更
| n ->
// n * (fact ...)は
// 呼び出し結果を使っている
n * (fact (n - 1))
let rec fact x k =
match x with
| 0 -> k 1
| n ->
fact (n - 1) (fun res ->
// 呼び出し結果を使って
// 呼び出し後の計算し、kに渡す
k (n * res)
)
TailCall
属性