call/ccとvalues

# valuesをcall/ccで定義できる理由がよく分かりません。誰か対応するcall-with-valuesを見せてください

みずぴー日記

call/cc版valuesに対応するcall-with-valuesがどうやって定義されるのかはよく分からないですが、call-with-valuesがあると継続が複数の引数をとるようになることを処理系が知ってなければいけないと思うので、やっぱりScheme上では定義できない気がしてます。


call-with-valuesをとりあえずブラックボックスとしておいて継続が複数の引数をとりうるとすれば、valuesがcall/ccで定義できるのは以下のように説明できるんじゃないでしょうか。ただし、説明は自分の直観的理解に基づいているので内容が不正確な可能性があります。あしからず。ツッコミ歓迎です。


たとえば次のようなコードを考える。

(define (return-true)
  (call/cc (lambda (cc) (cc #t))))

return-trueは単に#tを返す関数。これは次のように書き換えられる。

(define (return-true)
  #t)

つまり、call/ccが末尾位置で呼び出されていて、かつ、call/ccに渡された関数f内の末尾位置で継続を(外部に持ち出したりせずに)呼んでいるだけなら、call/ccを呼んでいる箇所にfのbodyを(必要ならばbeginで囲むなりして)展開することができます。逆にcall/ccを使わずにかかれた関数に対して適当な末尾位置にcall/ccを挿入して継続を呼ぶようにすることで元の関数を挙動を変えずに書き換えることもできるはずです。

これを踏まえれば、1個の値を返すバージョンのvaluesは

(define (value arg)
  (call/cc (lambda (cc) (cc arg))))

と定義できるし、同じように2個または任意個の値を返すものはそれぞれ、

(define (values2 arg1 arg2)
  (call/cc (lambda (cc) (cc arg1 arg2))))

(define (values . args)
  (call/cc (lambda (cc) (apply cc args))))

とできるでしょう。