10

I am redesigning a library and I am not happy with the current design pattern. This question concerns the use of the strategy pattern in conjunction with a State monad

I have a Filter. All it does, in its basic implementation, is to take a some datafeed of type 'd and update itself, generating a new updated copy of itself.

[<AbstractClass>]
type Filter<'d, 'F> (state: 'F) =
    member val StateVariable = state with get
    abstract member Update: 'd -> Filter<'d, 'F>

I have then a ISignalGenerator, that takes a filter, environmental data and process it to generate a Signal of type 'S.

type ISignalGenerator<'d, 'F, 'S> =
    abstract member GenerateSignal: 'd -> Filter<'d,'F> -> 'S

The SignalGenerator is a strategy pattern object. On SignalGenerator's implementations, the library user mounts the functions that will be used and combined to generate the Signal.

I could wrap my code in a state monad. Together with some environmental variables (the datafeed), the state monad will carry carry along 'Filter' as state. SignalGenerator will then get state updates via the state monad (the datafeed of type 'd and the Filter)

The design issue I have is that I'd like to decouple the SignalGenerator type from the development of the workflow, i.e. I'd like to avoid nesting the state monad in the belly of the SignalGenerator. Is there a functional design pattern to achieve this?

EDIT

Based on Tomas's comment, I have worked on a toy model. The choice of having a strategy class is based on the need to wrap together a number of functions.

/////////////////////////////////////////////////////////////////////////////////////
// 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

I was wondering if there would be a pattern solution where the Strategy class could consume the mounted functions without nesting the state monad in its belly. In other words, is there a way to postpone the definition of the let state = StateMonadBuilder<int> (), without landing in a type inference headache?

I am relatively new to functional programming and F#. Please let me know if my question even makes sense! Thanks.

Community
  • 1
  • 1
NoIdeaHowToFixThis
  • 4,484
  • 2
  • 34
  • 69
  • 7
    This is a hard question to answer, because it is talking about the details of your design without explaining what the high-level problem is. I think that if you explain how you get to the design that you currently have, people might be able to give you more useful answers. (In other words, I have no clue what you're trying to do here...) – Tomas Petricek Nov 27 '13 at 13:58
  • 4
    This **[XY-questions-post](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)** will help you to improve your question. – ekostadinov Oct 09 '14 at 06:14
  • I tried it with `let state = StateMonad<_>()` and the rest of the example worked. I also could leave out all other type annotations and just let type inference do it's work. Is that what you mean? – halcwb Jun 09 '16 at 18:18
  • It's unclear to me why the state monad is necessary or useful here. Why can't you just pass a function as an argument? – VoronoiPotato Aug 06 '19 at 16:42

0 Answers0