私は常に、アルゴリズムをまったく表現できないかどうかというより、利便性の問題として考えてきました。Mitchellの考案したプログラムのようなプログラムを本当に実行したい場合は、静的型付け言語で適切なTuring Machineシミュレーターを作成するだけです。
静的型システムの秘訣は、柔軟性があり、保守が容易なコードを記述できる場合にのみ、適切な種類の柔軟性を提供することです。
静的に型付けされた言語よりも動的に管理する方が簡単であると考えられるプログラム構造化手法の例をいくつか示します。
ジェネリックとコンテナー
ML(1973年頃)およびCLU(1974年頃)より前の静的型付き言語では、文字列の赤黒木、整数の赤黒木、浮動小数点数の赤黒木、または特定のタイプの要素の赤黒木Foo
。ただし、静的にチェックされ、これらのデータ型のいずれかを処理できる赤黒ツリーの単一の実装を作成することは困難(おそらく不可能)でした。問題を回避する方法は、(1)型システムから完全に抜け出すことでした(たとえば:void *
C)では、(2)何らかのマクロプリプロセッサを自分で作成し、必要な特定の各タイプのコードを生成するマクロを作成するか、(3)抽出されたタイプをチェックするLisp / Smalltalk(およびJava)アプローチを使用します。オブジェクトを動的に。
MLとCLUはそれぞれ、推論された型と明示的に宣言された(静的)パラメーター化された型の概念を導入しました。
サブタイプポリモーフィズム
Simula67(1967 年頃)およびHope(1977年頃)より前の静的型付き言語では、動的ディスパッチとすべてのサブタイプのケースをカバーしているかどうかの静的チェックの両方を行うことはできませんでした。多くの言語には何らかの形式のタグ付き共用体がありましたが、case
or switch
ステートメントまたはジャンプテーブルがすべての可能なタグをカバーすることを確認するのはプログラマの責任でした。
Simulaモデルに準拠する言語(C ++、Java、C#、Eiffel)は、サブクラスを抽象クラスに提供し、コンパイラは、各サブクラスが親クラスによって宣言されたすべてのメソッドを実装したことを確認できます。Hopeモデルに続く言語(SML / NJからHaskellまでのすべてのMLバリアント)には代数的サブタイプがあり、コンパイラーtypecase
はすべてのステートメントがすべてのサブタイプをカバーしていることを確認できます。
モンキーパッチとアスペクト指向プログラミング
動的型システムにより、さまざまなプロトタイピング手法がはるかに簡単になります。文字列から関数へのハッシュマップで型が表現される言語(Python、Javascript、Rubyなど)では、特定の型に依存するすべてのモジュールの動作を、それを表すハッシュマップを動的に変更するだけで簡単に変更できます。タイプ。
モンキーパッチを使用してプログラムの保守を困難にする明らかな方法はありますが、実際には「悪」ではなく「善」に使用できる方法もあります。特にアスペクト指向プログラミングでは、モンキーパッチングのような手法を使用して、仮想化ファイルシステムを指すようにファイルタイプを変更したり、「無料」のユニットテストインフラストラクチャを構築したり、単純な例外タイプを変更して、デバッグしやすくするために、ログメッセージがキャッチされるたびに出力します。
1970年代に主要な静的チェックのアイデアが利用可能になったジェネリックとサブタイプポリモーフィズムとは異なり、アスペクト指向プログラミングの静的チェックは(私が思うに)アクティブな研究分野です。2001年頃からAspectJという言語があることを除いて、私はそれについてあまり知りません。