Я переделываю библиотеку, и меня не устраивает текущий шаблон проектирования. Этот вопрос касается использования шаблона стратегии в сочетании с Монада состояния
У меня есть 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
.
Я мог бы обернуть свой код в монаду состояния. Вместе с некоторыми переменными окружения (потоком данных) монада состояния будет нести «Фильтр» как состояние. Затем SignalGenerator
будет получать обновления состояния через монаду состояния (поток данных типа '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#. Пожалуйста, дайте мне знать, если мой вопрос имеет смысл! Спасибо.
let state = StateMonad<_>()
, и остальная часть примера сработала. Я также мог бы пропустить все другие аннотации типов и просто позволить выводу типов делать свою работу. Это то, что ты имеешь в виду? - person halcwb   schedule 09.06.2016