型valuesの使い方
実装していると難しくてイヤになるのが型(type
のこと)です。
型関係の実装で一番難しいのはsubtypep
で、ひどいもんです。
今回は難しくはないものの簡単でもない、型values
について説明します。
命令values
ではなく、型values
の方ですので注意。
型とは、普通だったらtypep
やsubtypep
なんかで使うものです。
例えば、オブジェクトが整数かどうかを確認するには次のようにします。
* (typep 100 'integer) T * (typep :hello 'integer) NIL
上記で記載した'integer
というのが「型」です。
今回話題とするのは、型values
だけです。
この型は他の型とはかなり違っており、そもそもtypep
では使えません。
* (typep 100 'values) →エラー * (typep 100 '(values integer)) →エラー
型values
が使えるのは、次の2点限定となります。
- 型
function
の第2引数 - special operatorの
the
型values
というのは、値の返却値を指定する型なので、
そんなものを指定したい場合が上記の2点しか存在しないのです。
その上記2点だけという制約により、(not (values ...))
や
(and (values ...) ...)
という書き方が許されないことになります。
実装するうえでnot
, and
, or
が許容されないのは本当にありがたいことで、
この辺りの苦労はそのうちsubtypep
と一緒に話したいと思っています。
たぶんsubtypep
の実装ってどこにも情報がないと思いますので。
それでは型values
の例を示します。
(declaim (ftype (function * (values integer)) aaa)) →関数aaaは、第一返却値がinteger (the (values integer string) (call 10 20 30)) →call関数は第一返却値がintegerで第二返却値がstring
型values
は&optional
と&rest
も使えます。
例えば次の通り。
(values integer &optional string fixnum) (values t &rest integer)
型values
にはとても分かりづらいことが1つあります。
それはデフォルトでは&rest t
が指定されるということです。
(values integer)
と記載した場合、
(values integer &rest t)
と同じ意味になります。
さらに型function
でもthe
でも、values
と記載しなかった場合は、
自動的に(values xxx)
という意味になります。
つまり、次の3つの表記はすべて同一となります。
(the integer ...)
(the (values integer) ...)
(the (values integer &rest t) ...)
それでは&rest t
とはどういう意味でしょうか。
&rest t
はそれ以降の型が全て型t
であるという意味になります。
つまり、
(values integer)
は
(values integer t t t t t t .....)
という意味になるのです。
もし、ある関数の返却値がinteger
たった1つであるとわかっている場合、
(values integer)
と記載するのではなく、
(values integer &rest nil)
と記載するのが正しいことになります。
よくマクロに関係する関数なんかでは
(defun aaa () (values))
みたいに、返却値が全くないことを指定することがあります。
上記の関数の命令(values)
は正しいのですが、
もし返却値の型をvalues
で表現したい場合、
(values)
ではなく
(values &rest nil)
となります。
型(values)
だと何でも許容する型という意味になるので、
全く逆の意味として認識されることになるのです。
とはいっても、&rest t
が指定されていて困ることはあまりないでしょう。
厳密にoptimizerを利用したい場合は、
&rest nil
を指定しないとうまく行かないかもしれません。
最後に、型values
の&allow-other-keys
について話します。
ANSI Common Lispの規格書には、
型values
には&allow-other-keys
が指定できると記載されています。
http://clhs.lisp.se/Body/t_values.htm
Type Specifier VALUES values value-typespec value-typespec::= typespec* [&optional typespec*] [&rest typespec] [&allow-other-keys]
つまりこんな感じ
(values integer &allow-other-keys)
しかし型values
の引数に&key
の指定は許されて無いので、&allow-other-keys
は間違いじゃないかと言われています。
https://www.cliki.net/Issue%20VALUES-%26ALLOW-OTHER-KEYS
Issue VALUES-&ALLOW-OTHER-KEYS Problem Description: (values &allow-other-keys) matches the syntax for the VALUES type specifier, but the description doesn't say what it means. Because the syntax does not allow &key, &allow-other-keys was probably a mistake.
たぶんそのとおりであり、間違いなのでしょう。
引数&allow-other-keys
は使わないでおいたほうがいいと思います。