状態、手続き、OOP

これはオブジェクト指向 Advent Calendar 2014の7日目の記事です。

入力によって変化する状態をうまく扱うことはプログラミングにおいて重要である。この記事では、状態や手続きを扱うさまざまなアプローチを紹介、比較する。

手続き型プログラミング

命令の列である手続きを「定義」「呼び出し」する記述力を提供する。命令の結果として得られた値に依存して、次に行う手続きを決定するという性質が肝である。

コルーチン

手続きに区切りを設けることで、「途中まで実行された手続き」を値として扱う。手続きが持つ潜在的な状態を閉じ込めることができるため、柔軟性が高い。

第一級手続き型プログラミング

手続きをデータ構造の一つとして表現し、呼び出すだけではなく、手続きそのものに対する操作も可能にする。「手続きの結果として得られた値に依存して、次に行う手続きを決定する」性質に対応するものとしてモナドがある。モナドはHaskellやPureScriptでは非常によく使われている。

構造体とフィールド

複数の値をまとめて一つの値として扱うための構造。フィールドを指定して、値を取得したり更新したりできる。

第一級フィールド

フィールドを値で表現することにより、より柔軟に構造に対してアクセスできるようにする。第一級フィールドの利点は、それが対象とする構造と強く結びつけられていないことであり、例えばRGBを格納する構造に対し、色相、彩度、明度のフィールドを定義することも可能である。lensはもっとも完成された第一級フィールドの実装であり、フィールド同士の合成や、データ型からの自動生成などができる。

オブジェクト指向

「オブジェクト」と「メソッド」の仕組みを新たに提供する。オブジェクトに対してメソッドを呼び出すと、メソッドに関連付けられた手続きが呼び出され、オブジェクトの内部状態が変化する。オブジェクトの内部状態を表現するのに構造体の仕組みがよく使われている。また、インターフェイスがあれば内部状態の持ち方が異なっても同じように扱えるため、複雑な状態を持つアプリケーションの記述に特に有用である。

第一級オブジェクト指向

オブジェクト指向の諸概念を言語に組み込むのではなく、あくまでデータ構造で表現することで、より自由にオブジェクトを扱う。第一級オブジェクト指向においては、オブジェクトは手続きを手続きに変換するオートマトン、インターフェイスはメソッドの集合であり、継承はメソッドの集合の包含関係で表される。オブジェクト自体が合成可能であるほか、メソッドをモナドにすることで、メソッドを合成可能にもできる。従来のオブジェクト指向と異なり、副作用が常に表現できるわけではないため、ゲームのロジックなどを安全に記述するDSLに応用できる。第一級オブジェクト指向の実装としてobjectiveがある(作った)。

FRP(Functional Reactive Programming)

Behavior(時間によって連続的に変化する値)とEvent(飛び飛びの時間で発生する値)を扱う。BehaviorでEventを振り分けたり、Eventを畳み込んでBehaviorにしたりする関数を組み合わせてプログラムを記述する。入力と出力がはっきりしていれば、信号の流れを非常にきれいに表現できる。一方、手続き的な考え方との相性は良くないので注意する必要がある。FRPの実装として、netwire、Yampa、elerea、sodium、reactive-banana、ordreaなどがある。

まとめ

一般に、言語の組み込み機能として何かの機能を提供するより、型と値を用いて目的のものを実装するほうがより柔軟性が高い。目的が何であれ、型と値の記述力を重視するのが、最高のプログラミング体験への鍵であるとして、この記事を締め括ろう。