**Launch your smart contract idea in just 4 days**

1,664 reads

by Francis StokesJanuary 25th, 2018

This article is about how I rewrote my library **vec-la** in a functional programming style. **vec-la** is a small 2d linear algebra library that models vectors and matrices as *plain javascript arrays*. This article *is not about* math and linear algebra though — you don’t have to know that much to be able to get some value out of it.

In case you don’t know, a vector is basically an ordered collection of numbers. A *2D* vector is just an ordered collection of 2 numbers. If you’re familiar with coordinates like (2, 3) then you know what a vector is intuitively.

Vectors can be visualised as arrows on the plane

But a vector can also be seen as an arrow in space; It has a direction (where the arrow points to) and a magnitude (how long the arrow is). That’s important because it means that a vector can represent more than just points in space — it can just as well represent speed in a direction for instance.

In many ways, vectors are like normal numbers. You can add, subtract, and scale them, but you can do other cool stuff like rotate and reflect them. That’s what *vec-la* is all about — it gives you the tools to manipulate these mathematical objects programmatically.

I primarily use **vec-la** to build programatic animations and games, although the use cases for vectors and matrices are wide.

With all of that out of the way, the primary goal of both the original project and the refactor was to move away from the approach that many other libraries take; Class based vector models where operations are **methods** that mutate the vector.

Avoiding mutation of state is an idea that has become more and more widespread in the last few years. Redux in particular has brought this into the spotlight in the javascript community.

Instead, vec-la uses pure functions that always return a new copy. To illustrate these differences though, let me compare to another (much more popular) library, victor.js.

In the normal case Victor requires creating a specialised object, but it also exposes an API for creating from an array:

```
Victor.fromArray([15, 22])
```

Although actually ends up being more tedious than creating vectors with new.

Using **add**, you can see the idea of *mutation* coming in. The result of adding *vic1* to *vic2* is actually stored in *vic1*. This is annoying if you want to continue using *vic1* afterwards. *vec-la* will always return a new vector, and so you never have the mental burden of worrying about what happens to **vec1** and **vec2**.

Same here for multiply in *victor*— it mutates the vector your working with. This can often lead to unexpected and difficult to find bugs. To see why take the following code:

Victor also does not allow for some other more advanced functionality that *vec-la* does, like using matrices. If you don’t know what a matrix is, here is a simple but inexact explanation:

A matrix is a set of numbers arranged into a table. There is a special way to combine these numbers together with a vector or matrix that gives you a new vector or matrix. This operation is called Matrix multiplication. I find it helpful to think of a matrix as being the definition for a kind of transformation function.

Writing matrices by hand is cumbersome and difficult to read, so there is an API using a *fluent* builder pattern to simplify creation:

You might already say that *vec-la* is pretty functional.

- It works with functions, not methods
- It never mutates arguments
- Functions that take or return vectors plug easily together — they compose

But it has some drawbacks too:

- The functions are not curried
- They often take arguments in the “wrong” order
- The
introduces a specialised object into the mix which is not a plain array*matrixBuilder*

If you don’t know about currying and argument order, check out my article *Making Functional Programming Click**.* I go deep into detail about these concepts there.

Let’s see how to fix each of these drawbacks.

That’s a fairly easy fix, but it actually needs to be combined with fixing the argument order. As I stated in the article I just mentioned:

The rule is typically

put the data as the last argument

Most of the time that data is going to be the vector you want to operate on. Let’s use the **scale** function to see the problem:

This function takes a vector **v** and a scale factor **sc** as arguments. Because of that order, you cannot partially apply this function in a useful way; It’s much more likely that you want to scale *different* vectors by the same *scale* factor, than it is that you want to scale the *same* *vector* by *different* scaling factors. If you swap the arguments, you can make a more meaningful function.

There are a few more functions like this in the library. **transform** takes a vector and a matrix and transforms the vector according to the matrix. Let’s imagine that you have a shape defined by an array of vectors. If you want to transform every point, you could do this:

If we switch the arguments we can create a partially applied transform function that will always use our matrix:

That’s a lot more expressive and reusable. If you have another shape or point you can transform it using that same function. Before we were forced to create an arrow function that implicitly has access to the matrix.

As a last example (there are plenty more), there is a convenience function called **rotatePointAround**, which takes a vector to rotate, a vector to use as the rotation origin (control point), and an angle. If you want to rotate a bunch of vectors around the same point by the same angle, a better order would be angle, rotation origin, vector.

There’s a good possibility that you’re thinking of counter examples and exceptions, because they certainly exist. In those cases, we can use something called a combinator to rearrange the arguments on the fly. A combinator is any function that takes a function as input and produces a function as output.

Let’s imagine that we have a vector, and an array of matrices. We want to produce an array of vectors where the one vector is transformed by all of our different matrices. In this case, we want to flip the arguments of transform. Instead of writing a special custom function, we can write a generic combinator to achieve this:

It’s a less common use case, but having a function like **flip2** makes it easy to manage when it does come up. Like **curry**, you’ll find an implementation of **flip** in all the major functional libraries like ramda or sanctuary.

We’ve solved the first two problems, and kept the possibility of runtime argument rearrangement open if we need to handle unusual cases. But there is still the problem of the matrix builder.

All of the functions in the new library have been built to support function composition, but a fluent interface simply doesn’t; You have to keep calling methods until the matrix is ready, and then call *get()* to release the matrix value. (if you don’t know what function composition is, read the article I mentioned before)

Let’s take a look at the original matrixBuilder code.

The **vMatrixBuilder** function takes a matrix (or nothing, which implies the *identity matrix*) and returns an object with some methods for rotate, scale etc. From each of those methods, it returns a new matrixBuilder which composes the old matrix and a new one that performs a given operation.

That word compose should be jumping off the page at you right now. It turns out there is a way to take two matrices and perform a complicated sum of the numbers inside, and get a new one that encodes the information of both.

We call that operation matrix composition, and the crazy thing is that this works exactly the same function composition (of course it’s not really crazy — math tends to be a well thought out process of generalisation, so these types overlap happen a lot).

That’s probably the most intimidating piece of code in this whole article. I showed the **mCompose** function just to show that there is some kind of way to compose matrices, but understanding is not important (and is essentially impossible just from this implementation). If you want to know how all the math for this really works, I recommend 3blue1browns’s series on “The essence of linear algebra”.

The rest just works exactly the same as **matrixBuilder** — it creates matrices by partially applying **mCompose** to a specialised matrix. And just like **matrixBuilder,** you need to kick the whole thing off with a matrix, which is typically in both cases the identity matrix. The identity matrix, unsurprisingly, is just like the **identity** function in programming — when you apply it to a matrix or vector you just get the same thing you put in.

Now we can express a build up of matrices through pure function composition, and we’re not restricted to the kind of methods that one particular API exposes.

Reframing the library this way leads to a much higher interoperability with other libraries — especially functional ones like ramda, which I like to work with. To see an example of all of this coming together, check out this programatic animation on codepen.

I will admit that the matrix builder is an *easier* interface conceptually, but it trades off *flexibility* and *generality* to achieve that interface. I think both libraries and approaches have their place.

You can see both the new **vec-la-fp**, the original **vec****-la** on github. They are both around 150 lines of actual code, so it’s a pretty easy project to get your head around.

If you’ve enjoyed this article, let me know by leaving me a comment here or on twitter.

I’m starting a series called “exploring ramda” where I’ll be writing about incorporating a functional style in javascript using the ramda library, so follow me here on medium if that’s something that interests you.

L O A D I N G

. . . comments & more!

. . . comments & more!