型消去

badge

型消去とは、型引数に_を指定し、その情報をあえて捨てることです。型消去は多相型を持つ言語の多くが併せて持つ機能ですが、Ergの文法に即して言えば型引数消去といった方が正確でしょう。

もっともよく見られる型消去された型の例は[T, _]でしょう。配列はコンパイル時にその長さが分からない場合もあります。例えば、コマンドライン引数を指すsys.argv[Str, _]型です。コマンドライン引数の長さをErgのコンパイラは知りようがないため、長さに関する情報は諦めなくてはならないのです。 しかし、型消去された型は、されていない型のスーパータイプになる(e.g. [T; N] < [T; _])ため、より多くのオブジェクトを受け取れるようになります。 [T; N]型のオブジェクトはもちろん[T; _]型のメソッドを使用できますが、使用後nの情報は消去されます。長さが変わってしまっているかもしれないからです。長さが変わらないならばシグネチャで示さなくてはなりません。

# 配列の長さが変わらないことが保証される関数(sortなど)
f: [T; N] -> [T; N]
# 長さが保障されない関数(filterなど)
g: [T; n] -> [T; _]

型指定自体で_を使うとその型はObjectまでアップキャストされます。 型でない型引数(Int, Bool型など)の場合、_としたパラメータは未定義になります。

i: _ # i: Object
[_; _] == [Object; _] == Array

型消去は型指定の省略とは違います。一度型引数情報を消去してしまうと、再びアサーションしなければ情報は戻りません。

implicit = (1..5).iter().map(i -> i * 2).to_arr()
explicit = (1..5).iter().map(i -> i * 2).into(Array(Nat))

Rustでは以下のコードに対応します。


#![allow(unused)]
fn main() {
let partial = (1..6).iter().map(|i| i * 2).collect::<Vec<_>>();
}

Ergでは型の部分省略はできず、代わりに高階カインド多相を使用します。

# collectはカインドを受け取る高階カインドのメソッド
hk = (1..5).iter().map(i -> i * 2).collect(Array)
hk: Array(Int)