How does ELM interop with side effects in a purely functional way?

Hello all. Looking to learn some fundamental things about Elm. Background, I’m coming from C# so please be patient with me.

If the language can only deal in pure functions, how does it get input from the outside world? I think I have a rough idea, but please correct me.

The state of the world is seen as one big piece of data.

The current state of the world, W1, plus some arguments, are passed into Elm runtime.

Elm runtime evaluates, and spits out a new world state, W2, waiting for the next set of arguments.

Rinse and repeat. Basically like a REPL?

Check out the Elm guide. Specifically, the The Elm Architecture section describes what you’re looking for.

1 Like

The trick is to apply the immutable function(s) again when you get new input/events.
For example, you can model all events using a list. Each time you get an event or input, you append it to that list. (Yes, there is mutation happening, but this is in the framework, outside of the scope of the immutability constraint)
Your program then can be a function that takes that list with the history of inputs as input. So that immutable function can return a different value because it gets a different input.

Elm does the aggregation differently: Instead of that list, it uses a state model value threaded through applications of the update function.
Elm builds a chain of applications of the update function.

Yeah, that’s a really good summary.

I like the REPL analogy. I also tend to think of it in terms of an ASP.NET MVC app that doesn’t use two-way model-binding–data comes into the update function (router), which selects the correct message (controller) to updates the model (application state), and then evaluates a new version of the view (model binding).

If you’re from C# you might enjoy this series I wrote on how to do monads in C#. It’s shameless self-promotion, but it does honestly make my day-to-day in C# so much easier.

1 Like

Also, functions like Http.get, rather than initiating the call themselves, are basically just constructors for objects like {url = "http://foo", callback = someFunction } (pseudocode) Which are then handed to the runtime which does the actual request.

Functional languages also use IO Monads (called Task in Elm, Async in F#) which are chainable with an API similar to Task in C#. Unlike C# Tasks though which make the request as soon as they are created, you construct your chain of Elm Tasks and hand them to the runtime, or in F# (since it allows impure code) you pass it to Async.RunSynchronously() (or give it to your server framework) which makes all the calls.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.