Ceylon : Quick introduction 邦訳(3)


以下の邦訳 その3 です。

ceylon-lang.org

blog1.mammb.com

型エイリアスと型推論

型宣言を完全に明示した場合、理解しやすいというより難解なコードになりがちです。ジェネリック型の繰り返しが現れると、コードの可読性は著しく損なわれます。我々は以下のように考えています。

  1. ローカル宣言の型アノテーションを明示することは多くの場合、価値がない
  2. Javaで一般的なパラメータ化された同じ型引数の繰り返しは非常にうるさい


Ceylon は、ローカル宣言に型推論を持ち込むことで1つめの問題に対処します。例えば以下のように

value names = LinkedList { "Tom", "Dick", "Harry" };
 
function sqrt(Float x) { return x**0.5; }
 
for (item in order.items) { ... }


一方、宣言の外のコンパイル単位からアクセスされる宣言には、型アノテーションの明示が必要となります。我々はこれがコードをより読みやすく、より小さく、コンパイラにとっても効率的で、スタックオーバーフローの危険性を小さくすると考えています。


Ceylon は2つめの問題について型エイリアスを用いることで対処します。これは C における typedef と非常に似通ったものです。型エイリアスは型引数と組み合わせたジェネリック型の省略形として機能します。

interface Strings = List<String>;

我々は、この言語機能の利用を推奨しており、これだけでコードはより読みやすくなります。


高階関数

多くのプログラミング言語のように、Ceylon は関数機能を提供します。
他の関数で操作される関数は高階関数と呼ばれます。例えば、

void repeat(Integer times,
        void iterate(Integer i)) {
    for (i in 1..times) {
        iterate(i);
    }
} 


高階関数を起動する場合、名前付き関数として参照を渡すこともできます。

void printSqr(Integer i) {
    print(i**2);
}
 
repeat(5, printSqr);


または、関数をインライン化された引数として、次のようにすることもできます。

repeat(5, (Integer i) print(i**2));

名前付き引数を使ってた場合には以下のようにもできます。

repeat {
    times = 5;
    void iterate(Integer i) {
        print(i**2);
    }
};


メンバーメソッドや属性の参照についても高階関数へ渡すことができます。

String[] names = ... ;
String[] uppercaseNames = map(names, String.uppercase);

内包表記

値のストリームをフィルタリングし変換することはコンピュータが主に得意とすることの1つです。したがって、Ceylon はこれらの操作を特に簡素にするための特別な構文を提供します。シーケンスのインスタンス化や可変長引数によりリスト表現を与えれば、Ceylon では、どこでも内包表記を書くことができます。例えば以下の例では名前のシーケンスがインスタンス化されます。

{ for (p in people) p.firstName + " " + p.lastName }


以下の例では成人のシーケンスが得られます。

{ for (p in people) if (p.age>=18) p }

以下の例では、名前をキーとした Person の Map が生成されます。

HashMap { for (p in people) p.firstName + " " + p.lastName -> p }


雇用者の Set を生成するには以下のようにします。

HashSet { for (p in people) for (j in p.jobs) j.organization }


以下の例では、名前をフォーマットして表示するメソッド引数に内包表記を使っています。

print(", ".join { for (p in people) p.firstName + " " + p.lastName });

完全具象型(fully-reified types)により単純化されたジェネリクス

Ceylon はJavaスタイルのワイルドカードパラメータや未加工型(raw types)、またはどんな種類の存在型(existential type)もサポートしません。そして Ceylon はコンパイラは型システムの都合によるどんな種類の"non-denotable"型(Javaプログラムで書くことのできないコンパイラが内部的に扱う型で、ダイアモンド演算子による型推論の結果として発生する)も使わず、型引数における暗黙的な制約がありません。そのため、ジェネリクス関連のエラーメッセージは人間にも理解できる形で報告されます。


ワイルドカード型の代わりに、Ceylon では宣言サイトバリアンス(declaration-site variance)を提供します。型パラメータは、その宣言において、クラスやインターフェースにて共変(out)または反変(in)としてマークされます。

interface Correspondence<in Key, out Item> { ... }


Ceylon はジェネリック型について、より表現力豊かなシステムがあり、より明瞭でより標準化された構文により制約を表現できます。型パラメータの型制約宣言のための構文はクラスやインターフェース宣言と同じような見た目になります。

interface Producer<in Input, out Value>
        given Value(Input input) satisfies Container { ... }

Ceylon の型システムは完全に具象化されています。特に、この型引数の具象化により、Java におけるジェネリック型の型消去により生じる多くの問題が取り除かれます。



次回に続きます。
blog1.mammb.com