13

モナディックオブザーバブル/リアクティブパーサーを定義しています。これは連続クエリであるため、通常のパーサーとはまったく異なる動作をします。基になるタイプは次のとおりです。

IObservable<'a> -> IObservable<'b>

関数型言語でのさまざまなパーサーの実装を見ると、物事を定義するためのより適切な方法は、単一のケースで識別される共用体であるように思われます。

type Pattern<'a,'b> = Pattern of (IObservable<'a> -> IObservable<'b>)

つまり、基になる関数を抽出して使用する必要があります。

let find (Pattern p) = p

問題は、これは単なる慣例によるものなのか、それとも後の拡張を目的としたものなのか、それとも定義が変更されない場合でもこれを行う理由があるのか​​ということです。

ボーナスの質問:より便利な型署名のためだけの場合は、型エイリアスを使用しないのはなぜですか?

type Pattern<'a,'b> = IObservable<'a> -> IObservable<'b>

私はこれをかなり進んでいますが、DUを使用しないことによって構成可能性が影響を受けるケースは見つかりませんでした。

4

2 に答える 2

15

F# コンパイラは、型の省略形に関する情報を保持しないため、型の推論によるメリットはまったくありません。型シグネチャはプログラム仕様として理解できます。型チェッカーに仕事を任せることは、プログラムの正確性を保証する良い方法です。

型エイリアスの場合は、どこでも型注釈を明示的に指定する必要があります。

type Vector = float * float

// val add : float * float -> float * float -> Vector
let add ((x1, y1): Vector) ((x2, y2): Vector): Vector = (x1 + y1, x2 + y2)

ただし、DU を使用する場合の透明性は得られません。

type Vector = V of float * float

// val add : Vector -> Vector -> Vector
let add (V(x1, y1)) (V(x2, y2)) = V(x1 + y1, x2 + y2)

複雑なプログラムでは、明確な型シグネチャにより、構成可能性の維持が容易になります。

単一ケースの DU にケースを追加するのが簡単になるだけでなく、メンバー メソッドと静的メソッドを使用して DU を拡張するのも簡単になります。ToString()1 つの例は、きれいな印刷のために頻繁にオーバーライドすることです。

于 2012-04-14T09:02:20.143 に答える
0

私が理解していることから、単一のケースで識別されたユニオン型は、問題のドメインに意味的に関連する名前を提供するためにあります。

これは、セマンティクスの軽い抽象化リーク修正であり、それだけです。

于 2012-04-14T08:52:46.547 に答える