Functional JS: Creating a Command Loop
Tags: Technology, JavaScript, Software Development, Data Science, Programming

Alright that wasn’t so bad. Now we have the pieces we need to create our Sum Type constructor. Let’s do that now:

Defining the Sum Type constructor.

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!

The Result Sum Type.

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:

The Command Type.

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.

— 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 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 application

— 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 application process — 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, the CMD_PATTERN which we have yet to define. CMD_PATTERN will be the pattern that match will match our Command instances against. When the match is complete and has yielded a result emit is called, letting the listeners know that their request has been answered.

— 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, the which we have yet to define. will be the pattern that will match our Command instances against. When the is complete and has yielded a result is called, letting the listeners know that their request has been answered. listen — sets up the internal listeners object with an entry. When emit is called with a tag that’s registered on listeners , the function located at that key will be called with emit’s data parameter.

— sets up the internal object with an entry. When is called with a that’s registered on , the function located at that key will be called with emit’s data parameter. emit — iterates through listeners at the provided tag and calls registered functions with result .

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!