Practicing Functional Programming: Vectors

I've been on a bit of a functional programming kick lately, and it's all starting to click. I came across some vector math for character movement in games, and it seemed like a nice exercise to try out with a purely functional approach. Just because it's a commonly known language, I'm going to use JavaScript for this example.

const assert = require('assert');

const vector = x => y => f => f(x)(y);
const vectorX = x => y => x;
const vectorY = x => y => y;
const addScalar = x => y => x + y;

const addVector = v1 => v2 => vector
(
  addScalar(v1(vectorX))(v2(vectorX))
)
(
  addScalar(v1(vectorY))(v2(vectorY))
);

describe('vectors', () => {
  it('adds two vectors', () => {
    const result = addVector(vector(1)(0))(vector(2)(3));
    assert.equal(result(vectorX), 3);
    assert.equal(result(vectorY), 3);
  });
});

The hardest part was coming up with the function for representing a vector:

const vector = x => y => f => f(x)(y);

Compare that to the lambda calculus version:

λx.λy.λf.((f x) y)

If we imagine that we are taking a vector with x = 1 and y = 0, we'd call it like this:

vector(1)(0);

This gives us:

f => f(x)(y);

Or, if we make the equivalent simplification in the lambda calculus version, we get:

λf.((f x) y)

So the representation of a vector is accomplished by binding values for x and y, and applying another function to those parameters.

For funzies, let's suppose we want to feed vector to itself:

vector(1)(0)(vector);

This produces the same result! That has more to do with how the function is composed, but still thought provoking, nonetheless.

The next challenge is coming up with a representation for getting either the x or the y value of a vector. Now that we've seen that the vector function can apply a function to its x and y values, respectively, we can start there. Given vector(1)(0), we have a function that can apply another function to the 1 and 0. Our representation should be able to take both values so that we can pass it to the vector. Then, we already know what value we expect to get out of it:

const vectorX = x => y => x;
const vectorY = x => y => y;

Or, here is the lambda calculus version:

λx.λy.x
λx.λy.y

Given two arguments, arbitrarily return one of them. It's as simple as that. If we apply a vector to these functions we get the correct results:

vector(1)(0)(vectorX) // returns 1
vector(1)(0)(vectorY) // returns 0

Next up is defining addition for vectors. A vector has two values, which can be individually treated as scalar values. In order to add two vectors together, we add the individual x's and y's from both vectors together to produce new vector.

const addScalar = x => y => x + y;

Now, this isn't necessarily "pure" because it's just using the addition operator in JavaScript. To be more pure, we'd have to define a function that could be called like this:

add(x)(y)

Which would return the new value. Essentially, addScalar is called the same way, but is not defined in terms of functions. For the sake of simplicity, we can just save that for another exercise.

Now that we can effectively add two numbers together we can make the next leap to defining a function that adds two vectors together. Here's how we add the x values of two vectors (v1 and v2):

addScalar(v1(vectorX))(v2(vectorX))

And here's how we'd add the y values of these two vectors:

addScalar(v1(vectorY))(v2(vectorY))

Now we can create a new vector from these two values, giving us the final function:

const addVector = v1 => v2 => vector
(
  addScalar(v1(vectorX))(v2(vectorX))
)
(
  addScalar(v1(vectorY))(v2(vectorY))
);

I hope that this is helpful in some way to others that are just starting to cut their teeth in functional programming.

Show Comments