多値を学ぶ
まずは R6RS を読むのが正しいと思うのでやってみよう。
意識することは境界条件を見極めること。つまりはまりがちなテストケースを作れるくらいに仕様を熟知しようということ。
11.15 Control features
The continuations of all non-final expressions within a sequence of expressions, such as in lambda, begin, let, let*, letrec, letrec*, let-values, let*-values, case, and cond forms, usually take an arbitrary number of values.
[s] 式が並ぶような式の場合、一番末尾にある式以外はその継続が任意の個数の値をうけとる。
早速難しい。例えば
(lambda () A B C D)
のような式があるときのことを考えてみよう。上の文章によれば A B C のそれぞれの継続は任意の個数の値をとる。
逆に言えば D の継続は任意の個数の値を受け取れない。
D の継続は処理系全体で一番最後に評価される式である可能性があるから任意の個数を受け取れないという意味なのかな、もう少し先を読んでみよう。
Except for these and the continuations created by call-with-values, let-values, and let*-values, continuations implicitly accepting a single value, such as the continuations of
The effect of passing an inappropriate number of values to such a continuation is undefined.
ふむふむ少しずつわかってきたぞ。上に出てきた let 中にある式の継続や今回出てきた let-values などによって作られた継続が特別に任意の個数を受け取るのだけどもそれ以外の場合は継続は 1 個の値しか受け取りませんよと。
この時点では継続が値を受け取るということがどういうことかは分からない。
(call-with-values producer consumer) procedure
Producer must be a procedure and should accept zero arguments.
Consumer must be a procedure and should accept as many values as producer returns.
The call-with-values procedure calls producer with no arguments and a continuation that, when passed some values, calls the consumer procedure with those values as arguments.
The continuation for the call to consumer is the continuation of the call to call-with-values.
難しく書いてあるけど producer の返した値(複数かもしれない)を consumer に渡して処理を続けるのだよね。
(call-with-values (lambda () (values 4 5)) (lambda (a b) b)) => 5 (call-with-values * -) => -1
2つめの例は (*) が 1 を返し、それを - 手続きが受け取り -1 になる。
ここで注意すべきは call-with-values という名前にだまされて producer が必ず values の結果を返すと勘違いしないようにすることかな。
いやでも待てよ (lambda () (values 1)) と (lambda () 1) は同じ意味だからいいのか。
values のところで省略していたものをここで考えよう。values 以下のように定義できるよねという話。
処理系が values を実際にこのように実装するかはまた別問題だが仕様を理解するには良いと思う。
(define (values . things) (call-with-current-continuation (lambda (cont) (apply cont things))))
あれ? call-with-current-continuation の cont は1引数じゃなかったっけ?。仕様を見てみよう。
The escape procedure accepts the same number of arguments as the continuation of the original call to call-with-current-continuation.
勘違いしていた λ...