a shallow river in northeastern Italy, just south of Ravenna

[A]synchronous Functional Programming - Intro

Updated October 9, 2026 by Richard Tong, King of Technology at CLOUŢ

https://rubico.land/assets/rubico-logo-3-3.jpg

Hello, welcome to my series on a new paradigm built on top of the Functional Programming paradigm: [A]synchronous Functional Programming. The [A]synchronous Functional Programming paradigm generally follows the Functional Programming paradigm and is founded on the following principles:

  • asynchronous code should be simple

  • functional style should not care about async

  • functional transformations should be composable, performant, and simple to express

At its core, [A]synchronous Functional Programming, like Functional Programming, uses functions to construct programs, leading to code that is modular, predictable, and easy to reason about. [A]synchronous Functional Programming inherits the following concepts from Functional Programming:

First Class Functions

First class functions are functions as data types, as opposed to language constructs. A first class function can be passed to another function as an argument.

In the example below, square is a first class function.

>

Higher-Order Functions

Higher-order functions are functions that take other functions as arguments.

Here are some examples of higher-order functions in JavaScript:

  • .reduce() Method: Iterates through an array and returns a single value

  • .forEach() Method: Executes a callback function on each of the elements in an array in order

  • .map() Method: Returns a new array made up of the return values from the provided callback function

In the example below, logArgs is a higher-order function.

>

Pure Functions

Pure functions are functions that have the following characteristics:

  • No side effects: A pure function does not change any variables, data, or state outside its scope, nor does it modify any outside state referenced by variables inside of its scope (see immutability).

  • Deterministic output / Referential transparency / Idempotence: Given the same input, a pure function will always return the same output.

Pure functions have the following advantages:

  • Pure functions are easy to test - simply vary the input for full code coverage

  • Multiple pure functions can be executed in parallel without interfering with each other

  • Pure functions can be memoized

The function add is a pure function because it does not have any side effects (nothing changes outside of its scope) and it has deterministic output (calling add with 1 and 2 will always result in 3)

>

The following are examples of side effects

  • Modifying global variables (global variables are state outside the function's scope)

  • Writing to a file (file contents are state outside the function's scope)

  • Logging output to the console (console is state outside the function's scope)

  • Inserting, updating, or deleting data from a database (database storage is state outside the function's scope)

  • Sending a network request to an external http API (the API is an interface over state outside the function's scope)

  • Overwriting a key on an object passed as an argument to the function (the object passed to the function is considered state outside the function's scope)

Partial Application

Partial application is a technique in functional programming where a curry function is used to partially apply arguments to a function, returning a partially applied function that expects the remaining arguments of the function.

Here is an example of partial application:

>

Monad-Like Structures / Meaningful Objects

A monad-like structure or meaningful object is an object that has some meaning beyond its name, for example the Array class creates arrays that can store other data types, and the Promise class creates a promise that can either complete or fail with a result on completion or error on failure. Arrays and Promises are examples of a meaningful objects.

The below example shows a promise promiseB chaining functionality with its .then method in a meaningful way, as if to say "wait for promiseA to resolve, and then execute the result on completion as n, returning n + 2".

>

[A]synchronous Functional Programming

[A]synchronous Functional Programming builds on these concepts, extending the ideas of Functional Programming to modern JavaScript (ECMAScript 6 onwards). In particular, the [A]synchronous Functional Programming paradigm considers current asynchronous primitives (e.g. Promises and async/await) when creating modular and predictable programs composed of functions.

We can use the Rubico library to operate in the [A]synchronous Functional Programming paradigm.

>

Above we see a composition of functions created with the Rubico compose operator. compose allows us to chain together operations sequentially, the result of one function becoming the argument to the next. The above composition starts with the ids [1, 2, 3, 4, 5], then using the async-enabled Rubico map operator, makes a request for each id and parses out the response body. Each parsed out response body is then logged out with the Rubico forEach operator and the console.log function.

In the above example, console.log is a first-class function - it is provided to the higher order function forEach as an argument. map is also a higher order function, accepting the anonymous first-class function async id => {...}. This combination of higher order functions and first-class functions using compose is what is known as a "function composition". There are no pure functions in the above example.

Now consider an example with pure functions:

>

In the above example, add and square are pure functions. They are very simple, expressed almost as pure math. A given input to add or square would result in the same output for each invocation. The add function is provided as a first class function to the Rubico reduce operator, and the square function is provided as a first class function to the Rubico map operator. Both reduce and map operators are considered to be higher order functions.

The combination of first class and high order functions above is similar to what we have seen with compose in the previous example. The difference is the use of the operator pipe over compose, in this case instead of creating a function composition with compose we create a "function pipeline" with pipe.

We see a new operation in the above example with reduce. It takes the squared numbers from map(square) and adds them all together into a final sum. We see the operator tap as well - it allows us to provide an asynchronous function to the composition, logging out the squared numbers while waiting 500 milliseconds between each log. With tap, the return value of the provided function is unused, so we can expect the input to the reduce operation following the tap expression tap(async numbers => {...}) to be the same as the input to the tap expression.

Conclusion

This concludes the intro to the [A]synchronous Functional Programming paradigm.

If you are curious about Rubico and would like to get started, please visit Rubico's home page, rubico.land.

Transducers Crash Course

Updated October 9, 2026 by Richard Tong, King of Technology at CLOUŢ

A crash course on Rubico transducers.

[A]synchronous Functional Programming - Data Types

Updated October 9, 2026 by Richard Tong, King of Technology at CLOUŢ

/assets/monad.png

Data types in [A]synchronous Functional Programming.

[A]synchronous Functional Programming - Handling HTTP

Updated October 9, 2026 by Richard Tong, King of Technology at CLOUŢ

/assets/HTTP_logo.png

Handling HTTP in [A]synchronous Functional Programming.

[A]synchronous Functional Programming - Statements vs Expressions

Updated October 9, 2026 by Richard Tong, King of Technology at CLOUŢ

Statements vs Expressions in [A]synchronous Functional Programming.