Long living programs

Hi,
I’m pretty new to F# coming from C#. I have done some tutorials like “Handling a purchase request”.
In those examples a basket is created, some methods are provided to add/remove items, validation takes place, data is sent to some services to send email etc, order is persisted, basket dies -> done.

What I don’t get is how I would do/design a longer living program. Say a “Diagram designer”. The diagram designer would consist of a lot of different items like shapes, connection lines, texts, images, drawings etc.
Would I start with a huge aggregate root like “Project”? And every change (e.g. add a shape) would lead to a new project? Or would there be some lists defined holding all the items and there is no “Project” at all?

Where do all the different items live in a functional program?

Sorry, if this is a very broad question. But it’s something I really don’t get in my head.

Thx,
Sven

Hi @Sven. Your question is one I struggled with when I was learning functional programming too - I am unsure how common it is, but ultimately ‘just a single immutable model that becomes a different model’ doesnt seem to work with anything that might have to, say, wait for user input events etc.

There are two ways I’ve used and seen to resolve this, and the first might be the easiest: you want to look up a pattern called “functional core, imperative shell”. Your outermost code might include a mutable ‘state’ variable that contains the updated functional model. Your logic is all functional, translating this state to a new state which the outer shell then stores in the mutable variable etc. The outer shell would handle listening for input, persisting to DB etc, all the stuff that require side effects or involve systems you don’t control (like time). Its kind of the ‘best of both worlds’ pattern, particularly in F#, where you can do functional programming, OO programming, purely imperative etc all relatively easily.

The second approach is a bit more low level, and understands that the way a long running program works is basically it has a core loop running somewhere, with that loop polling for events, triggering changes etc. In F#, you could do this purely immutably using a recursive function that is tail call optimised: each invocation would do polling, trigger updates etc, with the new state passed to the next call of the function. Behind the scenes this gets optimised to a loop however, so its kind of smoke and mirrors.

Hope that helps!

@ChrisPritchard, yes that helps a lot! Now, I know that I haven’t missed an important idea of functional programming. Instead I have to watch out for a mutual “bridge” to the “real world” (at least in my mindset). I was thinking about the problem of user inputs, but forget to mention it in my post. Thanks for pointing this out.
All the tutorials are describing, more or less, a saga. It starts and then ends after a few steps with some persisted data. But that is not how desktop applications work. I already tried to find code of a desktop application written in F#, but no success so far.

Elmish.WPF might be worth a look: https://github.com/elmish/Elmish.WPF. It contains a number of sample programs that are all ‘desktop F#’. It should also introduce you to the excellent Elmish pattern, which I also use in my monogame framework: https://github.com/ChrisPritchard/Xelmish

In both cases, the Elmish pattern abstracts away the imperative shell, providing a nice functional view of the world. However the shell is still there: WPF is based on a core loop polling for events and updating bindings etc, whereas Monogame is barely more than a loop that calls an Update method at a set interval and a Draw method every game frame. The way this is hooked in is that Elmish has a ‘setState’ function that is used to extract the current model (and view state, depending on framework), sticking it in a local mutable variable until the next transformation is required.

1 Like

Scott Wlaschin is tackling this problem as well:

https://fsharpforfunandprofit.com/posts/13-ways-of-looking-at-a-turtle/#way4

I read that some time ago, but didn’t see that this tackles my problem…

1 Like