ライブラリを再設計していますが、現在の設計パターンに満足していません。この質問は、 State モナドと組み合わせた戦略パターンの使用に関するものです。
私は持っていFilter
ます。基本的な実装では、あるタイプのデータフィードを受け取り、'd
自分自身を更新して、自分自身の新しい更新されたコピーを生成するだけです。
[<AbstractClass>]
type Filter<'d, 'F> (state: 'F) =
member val StateVariable = state with get
abstract member Update: 'd -> Filter<'d, 'F>
次に、ISignalGenerator
フィルター、環境データを取得し、それを処理してSignal
タイプのを生成し'S
ます。
type ISignalGenerator<'d, 'F, 'S> =
abstract member GenerateSignal: 'd -> Filter<'d,'F> -> 'S
はSignalGenerator
戦略パターン オブジェクトです。の実装SignalGenerator
では、ライブラリ ユーザーは、Signal
.
コードをステート モナドでラップできます。いくつかの環境変数 (データフィード) とともに、状態モナドは状態として 'Filter' を運びます。SignalGenerator
次に、状態モナド ( type のデータフィードと ) を介して状態の更新を取得し'd
ますFilter
。
私が抱えている設計上の問題は、型をワークフローの開発から切り離したいということですSignalGenerator
。つまり、状態モナドを の腹に入れ子にするのを避けたいのSignalGenerator
です。これを達成するための機能的な設計パターンはありますか?
編集
トーマスさんのコメントをもとに、おもちゃの模型を作ってみました。戦略クラスを持つという選択は、多数の関数をまとめる必要性に基づいています。
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the state
/////////////////////////////////////////////////////////////////////////////////////
type StateFunc<'State, 'T> = 'State -> 'T * 'State
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the State monad type
/////////////////////////////////////////////////////////////////////////////////////
type StateMonadBuilder<'State>() =
// M<'T> -> M<'T>
member b.ReturnFrom a : StateFunc<'State, 'T> = a
// 'T -> M<'T>
member b.Return a : StateFunc<'State, 'T> = ( fun s -> a, s)
// M<'T> * ('T -> M<'U>) -> M<'U>
member b.Bind(p : StateFunc<_, 'T>, rest : 'T -> StateFunc<_,_>) : StateFunc<'State, 'U> =
(fun s ->
let a, s' = p s
rest a s')
// Getter for the whole state, this type signature is because it passes along the state & returns the state
member b.getState : StateFunc<'State, _> = (fun s -> s, s)
// Setter for the state
member b.putState (s:'State) : StateFunc<'State, _> = (fun _ -> (), s)
/////////////////////////////////////////////////////////////////////////////////////
// The actual example
/////////////////////////////////////////////////////////////////////////////////////
let state = StateMonadBuilder<int> ()
// DoubleFunctOne defines standard operations that remain always the same
type Strategy (functOne) =
member this.DoubleFunctOne (x: int) = state {
let! res = functOne x
return res * 2 }
// I introduce customization with the definition of this function.
// Whenever I need, I will swap the function with some other
let myFunctOne x = state {
let someOtherFun x = x + 10
let! currState = state.getState
return currState * someOtherFun x}
// Here I mount the custom function on the strategy class, so the Strategy.DoubleFunctOne can produce a result
// In order to do so, I need to keep the construction in the state monad
let strategy1 = state {
return Strategy (myFunctOne) }
// Here begins the client side. The client will consume the methods provided by my strategies.
// He should not be concerned by the construction of the strategies
// Ok, then, let's put our work in production
let test1 = (state {
let! strategy = strategy1
return! strategy.DoubleFunctOne 10 }) 9
Strategy
腹に状態モナドを入れ子にすることなく、クラスがマウントされた関数を消費できるパターンソリューションがあるかどうか疑問に思っていました。言い換えれば、let state = StateMonadBuilder<int> ()
型推論の頭痛の種に陥ることなく、 の定義を延期する方法はありますか?
私は関数型プログラミングと F# に比較的慣れていません。私の質問が理にかなっているかどうか教えてください! ありがとう。