call/cc
call-with-current-continuation
「呼ばれた時点の継続」を引数の関数に渡して実行する
呼ばれた時点の継続→現在の継続→current-continuation→CC
hoge/piyoみたいな関数名はSchemeの慣習
何が嬉しいのか
冗長な継続渡しで書かずに、継続を使いたい!という要望を叶える
どこからともなく継続を取り出せる
継続渡しには以下のメリデメがある
継続渡しは直接スタイルに比べて冗長なので、書き換えるのが面倒くさい しかし、継続をglobal変数に入れて外部から制御できるなど嬉しい点もある
この一長一短の継続渡しだが、この短所をcall/ccによって解決できる
つまり、直接スタイル(f x)で書いているのにも関わらず継続を操作することが出来る
じゃあf x contでのcontはどこから持ってくるのか?
call/ccがそれを提供してくれる
見比べてみるとわかりやすい
code:gauche(lisp)
; ①継続を使っていない関数。引数は2つ。
(define (process elt seed)
(print "found: " elt)
(cons elt seed))
; ②継続渡しにした。contを引数に取るので引数は3つ。
(define (process/cont elt seed cont)
(print "found: " elt)
(cont (cons elt seed)))
; ③継続を使っていない関数と同じ引数2つだが、内部で継続を使えている。
(define (process/cont elt seed)
(call/cc
(lambda (cont)
(print "fond: " elt)
(cont (cons elt seed)))))
call/ccを使えば、processを使う側の関数(の引数の型)も継続渡しにせずに済む
code:gauche(lisp)
; ①を引数に取るfind-fold関数を呼び出し
(find-fold odd? process '() '(1 2 3 4 5))
; ②を引数に取る為に、find-foldを定義し直す必要がある
; なぜなら、第2引数の関数は、継続を取るため、引数の数が異なるから
(find-fold2 odd? process/cont '() '(1 2 3 4 5))
; ③を引数に取る。①と同じfind-foldをそのまま使える。にも関わらず内部で継続を使える
(find-fold odd? process/cont '() '(1 2 3 4 5))
参考
こういう問題点がある
直接スタイルの関数は、CPSな関数を呼べない
一度CPSな関数を呼ぶと戻ってこれないから
code:イメージ.js
function directStyle() {
const a = ..
const b = ..
const hoge = CPS(a, b, fn);
// 一度CPS側に移動すると、ここに戻って来れない!
return ..
}
そうなん?そうか。
え、そうなん?別にそんな琴なくない?
(find-fold/cont odd? process/cont .. .. sum)だったらちゃんと25って返ってくるじゃん
暗黙の継続って、もはや直接スタイルとかCPSとか関係なく、全てのreturn値に対して継続が存在するってことか
callCC :: ((a -> b) -> b) -> bという感じの型
a -> bの部分がcont関数
call/cc (lambda (..) (..))というふうに書くことが多いのかな
継続の横取り
code:lisp
(define (breaker/cc proc break)
(lambda (elt seed)
(call/cc
(lambda (cont)
(set! next (lambda () (cont (proc elt seed))))
(call/cc
(lambda (cont0)
(find-fold odd? (breaker/cc process cont0)
'() '(1 2 3 4 5 6 7 8 9 10)))))
(next)
call/ccの定義
GaucheではないなにかのLispで書かれている
めちゃくちゃ文字化けしているので読めない
Lisp知らんのでGaucheに変換できない
文字コード変えたら見れたよmiyamonz.icon
https://gyazo.com/8947937fc40e7b03e035a8b9a5759dbd
sugoimrsekut.icon*2
日本語でもよくわからんmiyamonz.icon
#'が何だったか思い出せん
リードマクロの一種だったと思うのだが
functionがわからんので一旦諦めた
助かるmiyamonz.icon
実装されているところを見る
code:gosh
gosh> ,d call/cc
#<subr (call-with-current-continuation proc)> is an instance of class <procedure> Defined at "libproc.scm":64
slots:
required : 1
optcount : 0
info : (call-with-current-continuation proc)
Cで定義されているのでlispの定義が見れなかった
call/ccによって継続を取り出せる
call/ccによって、「これ以降の処理」を取り出せる
再実装できるのか