Catyの話。まずスキーマの例を挙げます。
type personProfile = {"name" : string, "age" : integer};
この定義だと、{"name": "坂東トン吉"} はageプロパティがないので非妥当になります。ageを省略可能とするなら次の定義です。
type personProfile = {"name" : string, "age" : integer?};
ここで、integer? のお尻の疑問符は、正規表現の疑問符と同じで「なくてもよい」という意味です。この疑問符を使うと、MaybeモナドとかOption型を表現できます。
type Maybe= T?;
type Option= T?; type MaybeInteger = Maybe
;
type OptionInteger = Option;
しかし現状では、T?, integer? のような型がトップレベルで出てくるのは禁止してます。配列の項目、オプジェクトのプロパティでは T? や integer? が使えます*1。
現実には、トップレベルで「?」を使いたいこともあります。例えば、逆数をとるコマンド(関数と思っていいです)のプロファイルは、次のように書きたい。
command inverse :: number -> number? ;
0の逆数は未定義なので、inverseの値の型がMaybeやOptionなのは自然です。
今のCatyにおいてトップレベルのnumber?が認められないのは、「未定義の値が未定義」だからです。未定義を示す値を入力や出力に使うことはできません。そんな値はそもそもないのですから。代わりに例外を投げるので、次のようなプロファイルにせざるを得ません。
command inverse :: number -> number throws DividedByZero ;
MaybeやOptionのユーザーは、未定義を含む型が例外よりずっと使いやすいことをご存知でしょう。Catyでは例外捕捉機構がないので、なおのこと、未定義を含む型/未定義を表す値は重要です。例外は常にプログラム(スクリプト)全体を強制終了させてしまうので困ることが多いのです。
それで、未定義を型システムにちゃんと組み入れて、トップレベルでも「?」を付けた型を定義できるようにしようと思っています。JSON仕様との互換性やその他の事情から、未定義値のリテラルを導入することはできませんが、未定義値を入力/出力に含むコマンドを認め、条件分岐に未定義のケースを書けるようにしようと、そう思っています。
*1:配列の任意の位置で「?」が使えるわけではありません。