Python 3で書かれた私のプログラムには、(非常に大きな)テーブルのような数値データ構造で始まり、特定のアルゴリズムに従って列を追加する場所がたくさんあります。(アルゴリズムは場所によって異なります。)
命令型アプローチで問題が発生したため、これを純粋関数アプローチに変換しようとしています(再利用が難しい、中間ステップをメモするのが難しい、「遅延」計算を実現するのが難しい、状態に依存しているためにバグが発生しやすいなど)。 。
このTable
クラスは、ディクショナリのディクショナリとして実装されます。外部ディクショナリには、row_id
;でインデックス付けされた行が含まれます。内部には、。でインデックス付けされた行内の値が含まれますcolumn_title
。テーブルのメソッドは非常に単純です。
# return the value at the specified row_id, column_title
get_value(self, row_id, column_title)
# return the inner dictionary representing row given by row_id
get_row(self, row_id)
# add a column new_column_title, defined by func
# func signature must be: take a row and return a value
add_column(self, new_column_title, func)
これまでは、元のテーブルに列を追加するだけで、各関数はテーブル全体を引数として取りました。純粋関数に移行するときは、すべての引数を不変にする必要があります。したがって、初期テーブルは不変になります。追加の列はスタンドアロン列として作成され、それらを必要とする関数にのみ渡されます。典型的な関数は、初期テーブルと、すでに作成されているいくつかの列を受け取り、新しい列を返します。
私が遭遇する問題は、スタンドアロン列(Column
)を実装する方法です。
それぞれを辞書にすることもできますが、とても高額なようです。実際、たとえば、各論理行の10個のフィールドに対して操作を実行する必要がある場合は、10個の辞書検索を実行する必要があります。さらに、各列にはキーと値の両方が含まれ、サイズが2倍になります。
Column
簡単なリストを作成し、row_idから配列インデックスへのマッピングへの参照をそのリストに格納できます。利点は、このマッピングを同じ初期テーブルに対応するすべての列で共有でき、一度検索すると、すべての列で機能することです。しかし、これは他の問題を引き起こしますか?
これを行う場合、さらに進んで、実際にマッピングを初期テーブル自体の中に保存できますか?また、オブジェクトからの参照を、Column
それらが作成された最初のテーブルに戻すことはできますか?機能的なアプローチを想像した方法とは大きく異なるように見えますが、すべてが不変であるため、それがどのような問題を引き起こすのかわかりません。
一般に、機能的アプローチは、引数の1つへの戻り値の参照を維持することに眉をひそめますか?とにかく議論はすでに知られているので、それが何か(最適化や遅延評価など)を壊すようなことはないようです。しかし、多分私は何かが欠けています。