スキーマ構文の変更案(ラフ)
他の構文との整合性がなくなってきたとかの理由で、スキーマ構文を変更の予定。
将来的には型関数(型変数を持つ型構築子、総称型)も認める方針として、現状では型演算子を多用することにする。
構文構成素
- 型定数:意味が定まった型の名前。string, null, anyなど。
- 型変数:未定な型を意味する。
- 型関数:型変数を含む型表現、型を受け取り型を返す関数(多くの場合、関手の対象部分)を意味する。
- 型演算子:型関数と同じだが、特殊な構文。
型定数
- integer
- number
- string
- boolean
- null
- array (新規)
- object (新規)
- never
- any
型演算子
- '?' オプショナル演算子(単項後置)
- '|' 排他的ユニオン演算子(2項中置)
- '&' インターセクション演算子(2項中置)
- '*' クリーニスター演算子(単項後置)
- '[', ']' 配列生成演算子(n項前後置)
- '{', '}' オブジェクト生成演算子(n項前後置)
- '@' タギング演算子(2項前置)
- '(', ')' 属性付加演算子(2項特殊)
型演算子の注意事項
- ユニオン演算子の被演算項は、複数のリテラル、または複数のタグ付き(暗黙タグ含む)型で、排他的でないといけない。
- クリーニスター演算子は、配列の内部、しかも最後でないと使えない。
- 属性付加演算子は、関数呼び出しと似た形式で型表現を修飾する。グルーピング用の丸括弧との区別は文脈で行う。
型ラムダ式
「type<型変数の並び> 型表現」という形を型ラムダ式と呼ぶ。typeの直後の型変数は束縛変数になる。型定数と型変数に本質的な違いはないが、型定数はラムダ束縛(型抽象)が禁止されている変数である。
通常のラムダ計算と同じように型ラムダ計算が定義できる。
型代入
構文上は、「型の名前」は型定数と同じである。単に事前に定義されてない名前がユーザー定義型の名前として使える。定義されてない、つまりまだ意味が定まってない型の名前には、自由に型を代入してよい。
aが型の名前(まだ定義されてない)、Eが型表現なら、a = E は合法な型代入文である。特に、a = type<_X1, ..., _Xn>E; を type a<_X1, ..., _Xn> = E; とも書く。これによって、aという名前の型関数が定義できる。
型引数リストが空 <> のときは常に省略する。スキーマ属性による修飾(あれば)は型引数の直後に付ける。
例
type list<_T> = [_T*];
type listMax100<_T> = [_T*](maxItems = 100);
type pair<_X, _Y> = [_X, _Y];
type objPair<_X, _Y> = {"fst":_X, "snd":_Y};
array, objectはもはや型名で、次のように事前定義されている。
type array = [any*];
type object = {*: any}; // 厳密にはany?だが、?は省略可能というコンベンション
上記のlist型関数(型引数が1つ)は、使用頻度が高いので事前定義としてもいいだろう。従来と違うのは、角括弧が山形括弧に変わることだけ。
問題
- このままでは、任意の高階型(通常の関数型(ベキ)を含めた高階型とは違う。型関数もまた型とみます高階型)が定義出来てしまうので制限しなくてはならない。
- 構文解析が破綻しないか検討する必要がある。