2009-12-09 10 views
5

F#で複数の継承レベルをモデル化する推奨される方法はありますか?識別された共用体を使用した複数レベルの継承のモデリング

C#で、次のようなもの取る:私はF#でこれをやった

class Expr { } 
class SourceExpr : Expr { } 
class JoinExpr : SourceExpr { } 
class TableExpr : SourceExpr { } 

を:

type SourceExpr = 
    | Join of JoinExpr 
    | Table of TableExpr 

type Expr = 
    | Source of SourceExpr 
    | ... 

は、より良い方法はありますか?これは継承と同じ多型性を提供しますか?

答えて

8

これ以上の情報がなければ、あまりにも規範的すぎるのは難しいです。あなたがしようとしていることに応じて、クラス階層や差別化された共用体(DU)を使用する方が意味があります。最も一般的な/矛盾したトレードオフは、クラス階層が「オープン」であり、DUは「クローズ」されていることです。つまり、新しい型をクラス階層に簡単に追加できますが、新しい操作(基本クラスの抽象メソッド)を追加するには、既存のクラスをすべて変更する必要があります。これとは対照的に、DUを使用すると、新しい演算(データ型に対してパターンが一致する関数)を簡単に追加できますが、新しいケース(サブクラス)を追加するには、型を再定義して、 。 (これは表現問題とも呼ばれます)

DUに適した典型的な例はコンパイラです。言語とツリー構造が固定されている言語抽象構文ツリーがありますが、コンパイラ内では多くの異なるツリー変換操作を作成できます。クラス階層に適した典型的な例は、UIフレームワークです。ウィジェットが提供しなければならないすべての操作(Draw、Resize、...)を定義するいくつかの基本クラスがありますが、ユーザーは独自のカスタムサブタイプを余分な機能で追加します。

+0

私はパーサーに取り組んでいます。だから、DUは正しい選択だと思います。しかし、他人から継承しているような表現があります。両方のソースであるJoinまたはTableを受け入れる関数があります。 Exprを受け入れる関数もありますが、Sourceは多くのオプションの1つです。私はOOの言葉でそれを考えることはできませんが、同じ種類の多態的な振る舞いを維持しながらこの比較的静的な階層をモデル化するより良い方法があるのだろうかと思います。 – Daniel

+0

型でモデリングするとうまくいくでしょう。 「同じ」ものでもある2つのタイプがある場合は、それらを区別して使用する新しいタイプを追加します。唯一の欠点は、より多くの解体をしなければならないということです。しかし、パターンマッチングとアクティブパターンが必要な場所では、かなり許容できます。私はかなり複雑な再帰型とFParsecパーサーでこれをやっています。 –

0

あなたはF#で継承を使用してクラスをモデル化することができます。または、あなたが表示するように区別された共用体を使用して要件をモデル化できます。

識別された共用体は、同じ種類の多型性の動作を許可しません。特に、新しいケースを追加した場合、すべてのパターン一致を修正する必要があります。

それは利点がありますが、私はF#で差別化された共用体でコードを書く傾向があり、C#での継承はありません....私は拡張性について特定の懸念があります。

あなたは差別化された組合を使って継承のレベルをモデリングしていません...あなたはリンゴとニンジンを比較しています。

両方のパラダイムで同じ要件をモデル化することができます...私はあなたのコンテキストで差別化された組合に行くでしょう....私はそれがコードを読むのが簡単になると思う....しかしそれは主観的です。

関連する問題