call/cc
call-with-current-continuation
「呼ばれた時点の継続」を引数の関数に渡して実行する
呼ばれた時点の継続→現在の継続→current-continuation→CC
Scheme言語の標準関数
hoge/piyoみたいな関数名はSchemeの慣習
ref Gaucheのvariableとprocedure#60a6247519827000006a6906
何が嬉しいのか
冗長な継続渡しで書かずに、継続を使いたい!という要望を叶える
どこからともなく継続を取り出せる
継続渡しには以下のメリデメがある
継続渡しは直接スタイルに比べて冗長なので、書き換えるのが面倒くさい
しかし、継続をglobal変数に入れて外部から制御できるなど嬉しい点もある
この一長一短の継続渡しだが、この短所をcall/ccによって解決できる
つまり、直接スタイル(f x)で書いているのにも関わらず継続を操作することが出来る
じゃあf x contでのcontはどこから持ってくるのか?
call/ccがそれを提供してくれる
もう少し詳細にはプログラミングGaucheの19章のコードをHaskellで書き直す#60fbde7b1982700000ff656fに書いた
見比べてみるとわかりやすい
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))
参考
/mrsekut-book-4873113482/308 (19.4 call/cc)~
#WIP
こういう問題点がある
直接スタイルの関数は、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関数
/mrsekut-p/call/cc#5f54dad11982700000fb7df8の型あってるかな、わからん
call/cc (lambda (..) (..))というふうに書くことが多いのかな
継続の横取り
code:lisp
(define (breaker/cc proc break)
(lambda (elt seed)
(call/cc
(lambda (cont)
(set! next (lambda () (cont (proc elt seed))))
(break #f)))))
(call/cc
(lambda (cont0)
(find-fold odd? (breaker/cc process cont0)
'() '(1 2 3 4 5 6 7 8 9 10)))))
(next)
call/ccの定義
http://www.jsk.t.u-tokyo.ac.jp/~inaba/soft4/soft4-scheme-interp/node31.html
GaucheではないなにかのLispで書かれている
めちゃくちゃ文字化けしているので読めない
Lisp知らんのでGaucheに変換できない
文字コード変えたら見れたよmiyamonz.icon
https://chrome.google.com/webstore/detail/charset/oenllhgkiiljibhfagbfogdbchhdchml/related
https://gyazo.com/8947937fc40e7b03e035a8b9a5759dbd
sugoimrsekut.icon*2
日本語でもよくわからんmiyamonz.icon
#'が何だったか思い出せん
リードマクロの一種だったと思うのだが
http://dev.ariel-networks.com/wp/archives/198
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
optional : #f
optcount : 0
locked : #f
currying : #f
constant : #f
info : (call-with-current-continuation proc)
setter : #f
libproc.scmの64行目だ
Cで定義されているのでlispの定義が見れなかった
https://github.com/shirok/Gauche/blob/5f2a7c001ce51deb0a6fd6d89f9517aebb808eb5/src/vm.c#L2777-L2794
call/ccによって継続を取り出せる
call/ccによって、「これ以降の処理」を取り出せる
#??
再実装できるのか