There has been some recent talk about the pipe operator coming to JS. I'm excited about this proposal but only now that I've struggled a bit learning functional patterns in Elm.

## What is a pipe operator?

A pipe operator "pipes" the output of one function into another.

So instead of writing

```
const result = c(b(a(x)));
```

Or, as I prefer, writing:

```
const one = a(x);
const two = b(one);
const result = c(two);
```

We could write:

```
const result = a(x) |> b |> c;
```

JavaScript has something similar with chaining methods like `.map()`

, `.filter()`

, and `.reduce()`

.

For that reason, I'll be using `.map()`

as a stand in for exploring piping in JS and what I learned from Elm.

## Mapping in JS and Elm

Let's start with a basic `.map()`

example:

```
const square = (n) => n ** 2;
console.log([1, 2, 3].map(square));
// [1, 4, 9]
```

What this does is apply the `square(n)`

function to every item in the array, and returns a new array with those squared values.

This is similar to the way things are done in Elm:

```
List.map square [1, 2, 3]
```

There is another way to write our code above in JS using an anonymous arrow function:

```
console.log([1, 2, 3].map(n => square(n)));
```

At first, these two may seem similar, but they're slightly different.

The `.map()`

syntax is like this:

```
Array.map(<function>)
```

In the first way, we're saying apply the `square(n)`

function to every item in the array.

The second way, we're saying apply this anonymous `<function>`

which returns the result of the `square(n)`

function to every item in the array.

The first syntax is common in functional languages; the second is not. We'll explore why in the next section.

## Partial application

Before getting right into partial application, let's create another function, this time for multiplying:

```
const multiply = (a, b) => a * b;
```

Unlike out `square(n)`

function, this function takes *two* parameters.

Let's try to multiply our array by 10. Using the first syntax, it would look like this:

```
console.log([1, 2, 3].map(multiply(10)));
// TypeError: NaN is not a function
```

That's frustrating! Because `multiply()`

takes two arguments, we can't use that first syntax.

We can. however, use the second style syntax:

```
console.log([1, 2, 3].map(n => multiply(10, n)));
// [ 10, 20, 30 ]
```

And, we can even combine these two arithmetic functions together using both syntaxes:

```
console.log([1, 2, 3].map(square).map(n => multiply(10, n)));
// [ 10, 40, 90 ]
```

But if we wanted/needed to use that first syntax (like in Elm). Then we have to use **Partial Application**.

Let's refactor our `multiply()`

function to employ partial application:

```
const multiplyPartial = (a) => (b) => a * b;
```

If you're a simple JavaScript developer like myself, that probably hurt your brain and caused you to shudder a little.

Instead of two parameters, `multiplyPartial`

is like two functions. The first function returns another function which returns the product of the two inputs.

With partial application, you can write a function like this

```
const multiplyPartial10 = multiplyPartial(10);
```

The `multiplyPartial10`

function can now take the `b`

argument, which returns the product of the two:

```
multiplyPartial10(4)
// 40
```

Returning to that error we got, using partial application we can do:

```
console.log([1, 2, 3].map(multiplyPartial(10)));
// [10, 20, 30]
// or even
console.log([1, 2, 3].map(multiplyPartial10));
// [10, 20, 30]
```

Again, the function `multiplyPartial(10)`

returns a function, and that function is applied to each element of the array.

## Mixing Types

In JavaScript, a function where the parameters are two different types is perfectly ok:

```
const mixedTypesOne = (a, b) => a.toUpperCase() + " " + (b * 10);
const mixedTypesTwo = (a, b) => b.toUpperCase() + " " + (a * 10);
```

Both of them give you:

```
console.log([1, 2, 3].map(n => mixedTypesOne("This number multiplied by 10 is", n)));
console.log([1, 2, 3].map(n => mixedTypesTwo(n, "This number multiplied by 10 is")));
// [
// 'THIS NUMBER MULTIPLIED BY 10 IS 10',
// 'THIS NUMBER MULTIPLIED BY 10 IS 20',
// 'THIS NUMBER MULTIPLIED BY 10 IS 30'
// ]
```

Regardless of which type comes first in the `mixedTypes`

function, using the arrow syntax in `map()`

we can pass in the correct argument.

Now let's refactor them using partial application:

```
const mixedTypesPartialOne = (a) => (b) => a.toUpperCase() + " " + (b * 10);
const mixedTypesPartialTwo = (a) => (b) => b.toUpperCase() + " " + (a * 10);
```

And running the first gives:

```
console.log([1, 2, 3].map(mixedTypesPartialOne("This number multiplied by 10 is")));
// [
// 'THIS NUMBER MULTIPLIED BY 10 IS 10',
// 'THIS NUMBER MULTIPLIED BY 10 IS 20',
// 'THIS NUMBER MULTIPLIED BY 10 IS 30'
// ]
```

But the second:

```
console.log([1, 2, 3].map(mixedTypesPartialTwo("This number multiplied by 10 is")));
// TypeError: b.toUpperCase is not a function
```

In `mixedTypesPartialTwo`

, the the argument passed in as `b`

is a number, not a string.

## So what?

As the above example demonstrated, piping and partial application don't always play well with some common JavaScript practices — namely, functions with two parameters.

In Elm, functions only take one argument,^{1} and partial application does the rest.

I'm excited for the pipe operator, but it does mean having to think a little differently about how to write code. I struggled with this concept a bit, so hopefully this can help others.

## Latest comments (0)