Elm Effects Made Simple

Expressive Code Through a Simple Abstraction

billperegoy
im-becoming-functional
4 min readJan 14, 2017

--

A Quick Review

In my previous post on making the model more modular, we ended up making some changes to the update function to make it easier to hide the complexity of potential nested records. We ended up converting a conventional update function like this:

to an update function that looked something like this.

This example assumes that we have created setter functionsfor each field in the model record. While this approach may feel like overkill for something so simple, it feels simple and clean. Plus, it pays big dividends when working with nested records. But we’ve missed one key point here. In this simplified example we are using Html.beginnerProgram which cannot deal with effects.

Adding Effects

Any significant application is going to need to talk to the outside world in some way so handling effects is important. Let’s change our update function to use the Html.program so we can look at the use of effects.

You’ll note that the update function now returns a tuple of a new Model and a possible effect. We’ve also added another case to show an update action that does initiate an effect.

This change bothers me as we’ve taken some very expressive code and muddled it up with the extra syntax required to return a tuple. This is a shame since in most cases, we won’t be initiating any effects.

Another Approach!

In Elm 0.17, the “bang” operator was introduced. This operator is defined in this way.

This means we could rewrite our update function to look like this.

This looks slightly cleaner but still looks a bit weird. We end up needing to wrap up an extra set of parentheses around the pipelined update operation and we still end up with the somewhat strange dangling “bang function.” I find that this extra noise takes away from the expressiveness of the code.

Abstracting the Commands

After my my previous post on this subject, I received this very nice suggestion from @wintvelt. He suggested that I create functions to use within the update pipeline that add the effects to the update result. Using this suggestion, I created these two functions.

You’ll note that each of these functions takes in a Model and returns the required tuple. One is used when you have no effects and the other takes a list of effects. Using these functions, we can now refactor the update function like this.

To me, this reads in a much cleaner and more expressive way. We consistently have a pipeline that consists of a number of operations on the model, followed by a function that adds the command.

Another Alternative

There are some other packages out there that address this problem in a more sophisticated way. One example is the elm-return package. This package revolves around this definition.

While I found this concept interesting, it is more geared towards applying it to nested components where you are trying to pass the (model, cmd) tuple through layers of Elm hierarchy. I found this to be overkill for the simpler examples I’ve been working with, but it looks like a great possibility for more complex applications.

Conclusion

By adding a couple layers of abstraction to the update function, we can create much more readable and expressive code. All of this abstraction comes from simple, pure functions so none of the underlying logic is obfuscated in many ways. I find myself looking for simple, explicit abstractions like this any time my code starts to feel unwieldy. Consistently looking for these improvements makes my Elm applications remain easy to read and maintain.

--

--

billperegoy
im-becoming-functional

Polyglot programmer exploring the possibilities of functional programming.