多値の話

多値を言語的にサポートするのかという話。

手続きの返り値の話

多くの言語で手続きはn-in 1-outです。
これは関数適用の字面上自然なことで、継続に渡す値は1個にしか見えません。

(+ 1 2 (hoge) 4)

hogeの関数適用は当然2個以上の値を返されても、
その継続から見たら1個しか渡さないで欲しいという気分です。

しかし、プログラムにおいて、手続きが2個以上の値を返したいタイミングが発生します。
一つの解決策が、返り値を構造化することです。

この手法の問題は、多値を返したくて構造化したのか、
本当にデータを構造化する手続きなのか構文上判別できないことです。
その意味の差異を知るのは、実装したプログラマのみになります。

多値の話

そこでプログラミング言語の中には、
多値を返す手続きを書く事ができるものがあります。
Common Lisp, Schemeもその言語の一つです。
多値に関してSchemeを例にとって説明します。

(define (uncons pair)
  (values (car pair) (cdr pair)))

; A
(call-with-values
  (lambda () (uncons '( 1 . 2 ))
  +)
==> 3

; B
(+ (uncons '( 1 . 2 )))
==> 1

valuesは多値を継続に渡す手続きで、
call-with-valuesは多値を元に関数適用する手続きです。
call-with-valuesの第一引数が呼び出されると、1 2という多値が返ります。
第二引数は、あたかも(apply + '(1 2))とされたかのように多値を受け取ります。

Schemeは簡潔さを好む言語なので、R5RSではこの2個の手続きのみで多値を扱いますが、
実用上では素のまま使用することは困難なので、
receive, values-list, nth-values, let-values等々補助手続きを用意します。

実際の利用例

  • 多重代入
  • 返り値の補助情報
  • 手続きのレポート機能
  • (処理形依存の)シーケンス処理効率化

本題

(define data '(1 2 3))

; C
(fold + 0 data)
==> 6

; D
(fold + 0 1 2 3)
==> ?

Dが6になる言語仕様が欲しいという今日このごろです。
実際はすぐに対応できてしまいます。

(define (values-fold f i . vals)
  (fold f i vals))

(values-fold + 0 1 2 3)
==> 6