You do not need to define interfaces to make the architecture pluggable in F #. Functions are already compiled.
You can write your Outside-In system, starting with the desired, general behavior of your system. For example, here a function that I recently wrote translates a “Consumer Survey” from a state in which a message was not received to a new state:
let idle shouldSleep sleep (nm : NoMessageData) : PollingConsumer = if shouldSleep nm then sleep () |> Untimed.withResult nm.Result |> ReadyState else StoppedState ()
This is a higher order function . While I was writing this, I found that it depends on the helper functions shouldSleep and sleep , so I added them to the argument list. Then the compiler automatically passes this, for example. shouldSleep must be of type NoMessageData -> bool . This function is dependent. The same goes for the sleep function.
As a second step, it turns out that a reasonable implementation of the shouldSleep function is as follows:
let shouldSleep idleTime stopBefore (nm : NoMessageData) = nm.Stopped + idleTime < stopBefore
Do not pay attention if you do not know what all this does. This is the composition of the functions that matter here. In this case, we learned that this special shouldSleep function is of type TimeSpan -> DateTimeOffset -> NoMessageData -> bool , which is not quite the same as NoMessageData -> bool .
This is pretty close, and you can use the partial function app to go the rest of the distance:
let now' = DateTimeOffset.Now let stopBefore' = now' + TimeSpan.FromSeconds 20. let idleTime' = TimeSpan.FromSeconds 5. let shouldSleep' = shouldSleep idleTime' stopBefore'
The shouldSleep' function is a partial application of the shouldSleep function and has the desired type NoMessageData -> bool . You can compose this function in the idle function along with the implementation of its sleep dependencies.
Since the lower order function is of the correct type (the correct signature of the function), it simply clicks into place ; no casting is required to achieve this.
The idle , shouldSleep and shouldSleep' can be defined in different modules in different libraries, and you can assemble them all together using a process similar to Pure DI .
If you want to see a more complete example of compiling an entire application from separate functions, I will give an example in my functional architecture with F # The course of pluralism.