Functional JS: Creating a Command Loop
Handling Impure Actions in a Pure Application
If you’ve been studying up on Functional Programming in JS, you’ve probably heard about pure and impure functions, and side-effects. If not, I’ll quickly recap — a pure function is one that when given the same parameter any number of times, for each of those invocations it will produce the same result. Pure functions should also have a tangible result. Impure functions on the other hand may produce a different result when given the same parameters. Something non-static is happening behind the scenes in these impure functions. Those non-static factors are called side-effects. Functional programmers always say, ‘avoid impure functions, avoid side-effects’, etc. The only problem is, eventually you’ll need to incur side-effects. This is because the meat of an application is often the side-effecting portion. Consider these actions:
- making an HTTP request,
- caching data locally,
- asking for the time,
- calling functions via
setInterval
, - generating a random number
These are all examples of side-effects. You’re probably doing many of these regularly in your code. So how can you keep code pure?
One way that pure functional languages like Haskell handle side-effects is by handling them apart from the main ‘pure’ application. So today I’m going to attempt to create a Command Loop to handle impure portions of our application code. I’ll be implementing the Command Loop in JavaScript. Reader beware, I will be making highly opinionated choices throughout this article related to functional programming!
Before we dive right into creating our Command Loop, let’s talk about some other features that functional languages employ. Specifically I’d like to talk about Pattern Matching and Sum Types. These features greatly improve the experience a developer will have with the Command Loop pattern which we will be implementing.
Let’s start with Sum Types. A Sum Type is an object Type who’s instances have specific structures called variants. They call them Sum Types because you can determine the number of variants that can exist by summing the number of variants defined. Because there is a finite and known number of variants per Sum Type, they play well with the other concept I mentioned, Pattern Matching. If we know what can exist, we can write code to account for the variants. Imagine a function that knows what variants can exist on a given type instance, and then determines the specific variant type and performs a function based on that variant’s data. That’s exactly what we’re going to write to start our Command Loop journey. I call this function match
. It will take an instance of a Sum Type object and a pattern to match against:

Ok that looks like a lot. Let’s go over that in depth, one portion at a time:
Symbols, Err, and Type Registry
The TAG
, MATCH
, and TYPE
variables are special Symbol type objects. You can key objects with Symbols, so I use them to hide implementation details that I don’t want the end user messing with. TYPE
will represent the type name of any variant that we construct from a certain Sum Type. TAG
is the specific variant name for any single instance of a Sum Type. MATCH
will be the key we hide our match
function implementation. err
is just a simple abstraction for throwing an Error, and the REGISTERED_TYPES
variable will hold onto the type names we will later define when we create the Sum Type constructor function.
Matchable
Matchable
is a constructor function that builds an object that can be matched in the match
function. Matchable
is the base type by which we will build all of our Sum Type instances. Thus, I’ll be using it as a mix-in object when we write the function to define Sum Type variants. Notice pvt
in it’s parameters. pvt
will be used to pass on data specific to a variant back to the match function. Passing it back from the constructor to the match function actually prevents it from being visible to the outside world, so once we create an instance it’s data becomes immutable.
Another important thing to look at in the Matchable
function is how we hide our match
function behavior behind the MATCH
Symbol. This way match
can match against any instance without having to know about how match
is implemented. Our instance-specific match takes a pattern (which will be an object with keys that correspond to the variant names expected), and optionally some data. The data is just so that we can inject custom data into the match function for special internal cases. Inside our match implementation, we look to see if our instance’s TAG
is in the pattern. If it is we call the function in the pattern passing that function our instance as a parameter. If our instance’s TAG
isn’t in the pattern, it will look for the WILD
value (which is _
). If neither our instance TAG
nor the WILD
value is present in the pattern, we will throw an error.
Match
The match function itself checks to ensure that our pattern doesn’t contain unexpected values, or non-tagged instances. Then it just looks to the instance’s implementation of of match located at the MATCH
key and calls it with the given pattern and injected data
, if any.
Alright that wasn’t so bad. Now we have the pieces we need to create our Sum Type constructor. Let’s do that now:

More heavy duty stuff. Let’s break it down once more. register_type
is an internal function that modifies the REGISTERED_TYPES
object to include the names of variants registered to a specific type. SumType
is a special constructor that builds extensible Sum Type variant objects and registers their names to the central registry. SumType
is fairly complicated so let’s go through it in detail.
SumType
takes two parameters, the name
of the type that we’re creating, and the constructors
object which will hold the definitions for our Sum Type variants. The first thing that we do in the SumType
function is declare a few const
type variables. T
will be our result’s namespace. Each variant constructor that we create will be placed inside of T
, which will eventually serve as the return value of SumType
. tags
is an object which simply aggregates the tag names for each variant to make it easy to pass them to register_type
. We deconstruct our constructors
object with Object.entries
. Then we iterate over the results. This is the bulk of the SumType
function. We place the tag name of the constructor into the tags
object (aggregating the tag names). Then we create a constructor function called result
to serve as the real constructor that gets called when we instantiate a variant of a Sum Type. It’s this result
constructor function that we mix-in Matchable
to, allowing us to sink the private data from our constructors
definition into the final instance MATCH
call. Finally, we place a function at T[tag]
that returns a new result
and set that function’s prototype to result
's prototype. Phew! Let’s see how we use it to create Sum Types!

Finally, we can build a Sum Type that has match
ing capabilities. Now we can see the beauty of what we’ve just enacted. We can construct our Sum Types using our newly defined SumType
function. We specify the shape of our variants’ data with simple arrow functions that return objects. Then when we call match
, that private data is injected into our pattern’s selected function.
Way back at the beginning of this article I was discussing impurity in code. Let’s imagine a Sum Type whose variants represent the impure actions that we can take in our code:

I call this type Command. It consists of variants to represent things like getting and setting local storage (Retrieve, Cache), generating a Random number, sending an asynchronous request (Fork), and receiving a Response. We also have the ability to set an Interval and perform a general side Effect (like logging to the console).
This guy is going to be the backbone of our Command Loop. Let’s finally start thinking about how to define the Command Loop. There are two aspects to account for — sending and receiving. We will want a way to push Commands into the loop, and a way to subscribe to the responses of the loop.

We have defined some internal functions for our command loop, two of which will be available on the returned object (command
and subscriptions
).
command
— this function is a part of the Command Loop’s exposed interface. It allows us to push a command into the internal queue and trigger a call to process the queue. It accepts a Pair of[tag, cmd]
which are a string and Command object respectively.subscriptions
— the other publicly exposed function of Command Loop. It allows us to pass a configuration object to define what types of responses we will be listening for on the ‘pure’ end of the applicationprocess
— this function is internal only and is the meat of the Command Loop’s functionality. It pulls the last item off of the internal queue and sends it through an internal constant, theCMD_PATTERN
which we have yet to define.CMD_PATTERN
will be the pattern thatmatch
will match our Command instances against. When thematch
is complete and has yielded a resultemit
is called, letting the listeners know that their request has been answered.listen
— sets up the internallisteners
object with an entry. Whenemit
is called with atag
that’s registered onlisteners
, the function located at that key will be called with emit’s data parameter.emit
— iterates through listeners at the providedtag
and calls registered functions withresult
.
We’re getting close to our goal now. But we have another hurdle — we still need to define the match pattern CMD_PATTERN
that we’ll be sending our Commands through. Remember Result
that we defined earlier? We’ll be using it heavily here.

Cache
and Retrieve
are simple enough to implement. We just call the impure code as we normally would. Except its all neatly separated on it’s own impure track. Everything that we return is neatly wrapped up in a Result type. We also handle the default case using _
. Now let’s implement some others

Interval
Random
and Effect
are all very simple as well. Interval
sets an interval and returns a function to clear it. Random
gets a random number and gives it back to our application. Effect
takes any impure, non-returning function and calls it.
Now the tricky ones, Fork
and Response
. We’re going to have to go back to the drawing board for this one. Let’s define a type to encapsulate an Asynchronous action:

I’m not going to explain Async
in detail because it’s beyond the scope of this article, but know that it’s like a Promise, except to make it start its internal process, you must call its .fork
method, providing an on-error function and an on-success function as parameters. You can use chain
to wrap other Asyncs into the call or transform the expected result with map
. I’ve also included a function called fetch
that wraps an XMLHttpRequest
into the Async’s internal fork
. That’s the function that I’m concerned about for implementing our Fork
Command.

Now we will be expecting that the data passed into Fork
will be of the Async type. We can now fork it, calling command
again to send the value back to the pure side of the application as a Response
variant. Since we’re wrapping the result of our Async call in a Result (look how we have Response(Ok(x))
and Response(Err(x))
for the success and error paths of .fork
) we can just return the result. Response
only gives us a convenient way to give back the result of our impure asynchronous code to the pure side of the application in a controlled fashion.
Now the moment of truth. Will it work?!

We isolate our impure actions within the configuration object passed to subscriptions
. The keys of the object correspond to the tag passed to command
. When emit
is called internally, it passes the result of our impure code (if any) back to our pure application, where we can handle it within subscriptions
. As seen in the Interval example, you can nest commands within commands. IntervalIter
will log to the console and increment iterations
using Effect
. In the subscriptions
portion, we can check when iterations
is beyond a certain point and respond to it by cancelling the interval call.
Using the Fork
Command, we can make an asynchronous HTTP request, and on the subscriptions
side, we can respond in the Response
function. In this case we fire a new Effect command to log the results. Notice how we omit the String parameter of the (String, Command) pair using the ,
. We can do this for commands that we don’t care about subscribing to — they simply wont emit a result.
Now whenever we want to separate our effects we can use this tiny bit of code to do so. It doesn’t seem that tiny, but I call it tiny because we’ve managed to include all this functionality, including the Async type and several others, in just about 200 lines of code. That’s really not a lot considering how useful match
and SumType
can be together. Using just this code and vanillaJS we could accomplish a pretty polished separation of pure and impure code. But since it just separates side-effects from your code, we could probably toss the Command Loop into something like a React application, too.
Here’s a pen to hack at:
Hope you enjoyed another Functionally oriented article, and until next time FP on!