恒等関数としての values

再び多値関連の小ネタです。

PLT Scheme のあるライブラリを見ていて、こんな values の使い方を発見しました。

(filter values (list ...))

一瞬 values が再定義されているのかな?と思って辺りを探したんですが何も無く、試しにやってみると

> (filter values '(1 2 #f 3 4 #f 5))
(1 2 3 4 5)

おお。

> (map values '(1 2 #f 3 4 #f 5))
(1 2 #f 3 4 #f 5)

なるほど。

前回驚いた時と同様、「多値」イコール「2つ以上の値」という固定観念から抜け出せていなかったようです。このように1つの値に適用された場合は、ただの恒等関数 (\x = x) として機能するわけですね。

じゃぁ0値の場合はどうなるんでしょうか?

> (values)
>

REPL での見かけ上は void 値を評価した時と同じです:

> (void)
>

ということは?

> (void? (values))
context expected 1 value, received 0 values

 === context ===
d:\MzScheme\collects\scheme\private\misc.ss:68:7

おぉ、void ですら無い、と。

じゃぁこんな風に0引数関数を呼ぶこともできる、ということですね

> (call-with-values
      (lambda () (values))
    (lambda () 'nullary))
nullary

理解しました。

応用すると、適当に値を集めてきてその数によって分岐処理をする、みたいな事も可能になるわけです:

(call-with-values
    (lambda ()
      (apply values variable-length-list))
  (case-lambda
    (() 'nullary)
    ((x) 'unary)
    ((x y) 'binary)))