静的言語の多くの「優雅さ」の問題については、静的型チェック自体が原因ではなく、言語に実装されている静的型システムの表現力の欠如とコンパイラの制限された機能が原因であると確信しています。これが「より適切に」(たとえば Haskell のように) 行われると、突然、プログラムは簡潔でエレガントになり、動的なプログラムよりも安全になります。
以下に例を示します (C++ 固有、申し訳ありません)。C++ は非常に強力であるため、テンプレート クラス システムを使用してメタ言語を実装します。それでも、非常に単純な関数を宣言するのは困難です。
template<class X,class Y>
? max(X x, Y y)
boost::variant<X,Y>
?=や ?= の計算など、驚くほど多くの可能な解決策がありますが、is_convertible(X,Y)?(X:is_convertible(Y,X):Y:error)
実際に満足できるものはありません。
しかし、ここで、入力プログラムを同等の継続渡しスタイル形式に変換できるプリプロセッサを想像してみてください。各継続は、すべての可能な引数型を受け入れる呼び出し可能なオブジェクトです。max の CPS バージョンは次のようになります。
template<class X, class Y, class C>
void cps_max(X x, Y y, C cont) // cont is a object which can be called with X or Y
{
if (x>y) cont(x); else cont(y);
}
問題はなくなり、max は X または Y を受け入れる継続を呼び出します。そのため、静的型チェックを使用した max の解決策がありますが、max を非 CPS 形式で表現することはできませんuntransform(cps_max)
。いわば未定義です。したがって、正しく行うことができるいくつかの議論がmax
ありますが、そうする手段がありません。これは表現力の欠如です。
2501 の更新:関連のない型 X と Y
がいくつかあり、 bool operator<(X,Y)
. 何をmax(X,Y)
返す必要がありますか?さらに、X と Y の両方にメンバー関数があると仮定しますfoo();
。どうすれば次のように書けるようになるでしょうか:
void f(X x, Y y) {
max(X,Y).foo();
}
X または Y のいずれかを返し、その結果に対して foo() を呼び出すことは、動的言語では問題ありませんが、ほとんどの静的言語ではほぼ不可能です。ただし、cps_max を使用するように f() を書き換えることで、意図した機能を実現できます。
struct call_foo { template<class T> void operator(const T &t) const { t.foo(); } };
void f(X x, Y y) {
cps_max(x,y,call_foo());
}
したがって、これは静的型チェックの問題にはなりませんが、見た目が非常に悪く、単純な例を超えて拡張することはできません。この静的言語に欠けているのは、静的で読みやすいソリューションを提供できないことです。