Can functional programming not be as weird?

Stawiarski Jakub
4 min readJan 29, 2022
Image by Pixapopz from Pixabay.

Some time ago I came across this blog post that describes how functional programming (FP) is weird. The author tried (and almost succeeded) to translate a cake recipe into FP pseudocode. Besides giving me a good laugh it also made me think — can we make it be a little less weird?

One of the issues that always made understanding some of the concepts of FP difficult to me was the fact, that large parts of the community around it seem to favor brevity over readability. For example, a cake recipe could be much more readable if one was to use function composition. While this concept could be written down in terms of h(x) = f(g(x)) on some mathematicians chalkboard and then be wiped out of existence a minute later, understanding its usage in code of some enterprise solution that needs to be maintainable for years can be a different matter completely.

Can we build functional composition that would offer good type safety and would result in code that would read (almost) like plain English in TypeScript? Seems to be an interesting puzzle to do over the weekend, so let’s try.

Recipe building blocks

Let’s first decompose a cake recipe into a set of small functions, to show the need for functional composition.

Two things to note here. I will not follow all the steps of the original recipe mentioned in the blog post above. That would make the code too verbose for this simple example. Secondly, I will intentionally not follow some good practices around error handling just to show how we could use some existing legacy code and still have the result be quite nice.

Now, to get a cake all we have to do is:

…yuck. Maybe this seems fine to you if your native language is written right-to-left. For me, the need to read it from the inside out makes it seem a bit backward.

Implementing function composition

Let’s define the interface we will be working with.

Whoa, that’s a lot of generic types. We used full words instead of traditional single-letter names for them. The goal is to favor readability over brevity, right?

Let’s unpack this in steps. While TypeScript already has a Function type it’s not generic enough for our needs, so we declared our own. We used a call signature to describe a function that declares one or more parameters of some unknown type, and returns some specific OUTPUT .

We then declared a CompositeFunction that extends (or is a) Function , but also has an andThen property. This uses the fact, that function in TypeScript (and JavaScript) are actually just objects and can have additional properties. The andThen is a higher-order function as it accepts a function as an argument. Note, that the passed function must accept only a single argument that is the same type as the result of our composite so far. By calling andThen we get a new CompositeFunction, which still accepts the same argument types as the original one, but which has a new return type.

Calling the composite gives us a result of type OUTPUT | Error . This will work similarly to a Either type and forces us to remember the error handling before trying to use the returned value somehow.

Now, that we have a way of describing the composite functions and adding more functions to them, let’s declare a function that will allow us to start creating them.

The link to the repository is in the summary if somebody is interested in implementation details.

We use the built-in Parameters and ReturnType types so that the initial CompositeFunction has the same signature as the function we pass in. The second parameter may come in handy depending on the naming convention of the functions we want to compose later on.

Let’s also declare some aliases and helper functions, too.

Usage

Let’s finally compose our recipe out of the building blocks. Now, instead of this :

We can write this:

Maybe it’s just the brain damage I got from all the years spent reading Java, but this seems much more readable to me. If it isn’t for you, you might need to ignore the brackets and get used to camel case a bit more.

Remember how the decomposed functions threw some errors (or even strings)? Those will be caught and returned instead, no matter in which step they occur.

As a bonus, depending on the naming conventions we could use a different alias for the compose function and skip the helpers, like this:

More serious usage

Now, let’s imagine we are building an app that allows the user to upload some images. This could be written down as :

To make it really usable we would need to handle asynchronous results, too. That seems like a nice puzzle for one of the upcoming weekends.

Summary

This was a fun weekend project, but can be taken a lot further. Hopefully, you had as much fun reading about it as I had creating it.

If somebody wants to play around with the code I created a repository and published the results to npm.

--

--