多値を返す関数での再帰。

先日のエントリで多値を返す関数について考えてみましたが、`call-with-values' に渡せる手続きに引数が渡せないことから、再帰的に利用することができなさそうに感じていました。

しかし、よくよく考えれば、そんなことは無いですね。

二つの引数 a, b をとって、a > b なら、二つの値を近付けて行き、最も近くなる値、つまり、中間地点の近似値を得る手続きを考えてみます。
;; こういう意味の無いものしか用例として浮かばないところが、多値を扱う関数の用途を理解していないことを如実に現わしていますね。(特に再帰で)

(define (midvals a b)
  (if (<= a b)
      (values a b)
      (call-with-values (lambda () (values (- a 1) (+ b 1))) midvals)))
=> midvals
(midvals 100 2)
=> 51, 51
(midvals 2001 2)
=> 1001, 1002
(midvals 65536 128)
=> 32832, 32832

基本的には第一引数の方が大きいことを仮定していますので、最初から第一引数の方が小さいときには何もしないで終わってしまいますけど。

こうしてみると、それほど面倒な訳ではないですが、多値を返すことができるというメリットもまた、それほどには感じられなく思ってしまいます。
この戻り値を利用するときも、

(call-with-values (lambda () (midvals 65536 128)) cons)
=> (32832 . 32832)
(receive all (midvals 65536 128) all)
=> (32832 32832)
(let-values (((a b) (midvals 65535 128)))
  (print "a:" a ", b:" b))
a:32831, b:32832
=> #<undef>

とか、

(define-values (a b) (midvals 65535 128))
=> #<undef>
a
=> 32831
b
=> 32832

などとしなければならないんですよね。
どうも、特殊なことをしないとならないというのは Scheme らしくないと言いますか。

良く知りもしないで偉そうなこと書いてますね。どなたか識者の方に教えて頂きたいところです。(他力本願モードですみません)

今のところの感触ですと、Perl の、

引数群はリストとして渡され、戻り値を複数指定したときもリストとして返される。後は好きにして。

というモデルの方が合理的な気がしてしまいます。