Over the last year or so I've been learning functional programming (FP) and trying to fold it into my basic approach to software. I'd like to frame it here the way I'd teach it to someone who knows JS but doesn't know FP. There are far better resources I can point you to, but here's my take, as I can't seem to stop thinking about this stuff and I wanted to put it all in one place.

So. Assuming decent knowledge of JS, you know that JS is a wild beast of dynamism and willful trickery. 🐲 With FP, we can keep using all the underlying awesomeness, but we can add clarity, decrease cognitive load and drastically improve maintenance and readability. 😍

(Edit: we'll be using `ramda` as our functional library of choice, but it is interchangeable with many other functional libraries.)

We'll use some definitions as our starting point for these ideas.

#### Arity

`Arity` is the number of arguments a function expects. It is a simple thing, but with FP you start paying a lot of attention to the arity of a function, as each parameter can be thought of as a task / dependency:

```  ```const taskSolver = (taskOne) => {
// we have to _do_ something with the `taskOne` parameter
}
```
```

Until we deal with the `taskOne` parameter above, our function doesn't make any sense. (Either we shouldn't have defined the parameter or we are practicing willful obtuseness, and really, what is the point of doing anything? 👻 )

#### Nullary functions

A `nullary` function has an arity of zero, meaning it has zero parameters and returns one value. These are functions which take nothing and return something. They get their kicks for free.

Examples: `Math.random`; `Date.now`

#### Pure functions

One thing you're always striving for in FP are `pure` functions. These are really nice variations on your standard JS insanity-closures. Instead of everything that JS offers and can do, all tricky-like, pure functions have two great qualities:

• they are `deterministic`, meaning given the same input, they will always return the same output
• (Edit: I previously mentioned pure functions being `idempotent` here instead of qualifying them as `deterministic`; please see the comments for a further definition of `idempotent`, it has greater meaning than I previously understood. Thanks Rick Medina and Scott Sauyet for the corrections!)
• they have no side-effects, meaning no part of the program external to the function will be manipulated, modified or otherwise maligned.
• (Edit: I neglected to mention one of the most helpful properties of pure functions, which is that because they are deterministic, they also exhibit `referential transparency`, which means that a function invoked with all of its parameters is interchangeable with its output, e.g. `const double = (x) => x * 2; double(5) * double(3) // 10 * double(3) // 10 * 6 // 60` Thanks Eric Elliott!)

The simplest pure function is ultimately far more useful than it appears:

```  ```const identity = (x) => x
```
```

Which brings us to:

#### Unary functions

`Unary` functions are functions with an arity of one. These are functions which take a thing and return a thing.

Examples: `Math.sqrt`; `parseFloat`

These are ideal in FP land, as they really lend themselves to composition, which we will get to a bit later, and higher-order functions.

One thing you start to strive for in FP-land is understanding the common patterns and generating generic versions of a function that solve all variations.

This would be impossible without:

#### Higher-order functions

`Higher-order` functions take a function as an input and/or return a function as an output. These allow you to make simple functions far more powerful. By augmenting the input function and returning a wrapped function, we can both extricate the explicit task resolution (the function being passed in has privileged access and can be defined elsewhere) and we can automate common patterns and utilize them in the wrapped function.

The most common example here would probably be `map`, which is one of the coolest. 😎

#### Binary functions

`Binary` functions are functions which take two inputs and return one output.

`map` is a binary function.

```  ```const {R} = window // Ramda used, but others possible
const {map} = R
```
```

`map` takes a unary function that knows how to operate on one value,

```  ```const double = (x) => 2 * x
const input = 5
const output = double(input)
console.log(output) // 10
```
```

And changes it so that it can operate on an array of values:

```  ```const input = [1,2,3,4,5]
const output = map(double, input)
console.log(output) // [2,4,6,8,10]
```
```

Maybe you already know about `map`, but know it as the native `Array.prototype.map` instead, which isn't as reusable, but follows the same pattern:

```  ```[1,2,3,4,5].map(double) // [2,4,6,8,10]
```
```

When I say not as reusable, it's because I didn't show you the full coolness of the `Ramda.map` we're using above. `Ramda.map` is a curried function. 😏

#### Curry

When we `curry` a function, we make it so that until we provide all the parameters, we keep getting back a new function which expects the remaining parameters.

If we come back to our `double` definition above:

```  ```const double = (x) => 2 * x
```
```

We have hardcoded a `2` into the function. What if we wanted to make it so that we could pass in that value? We'd need to transform it into a binary function:

```  ```const multiply = (x, y) => y * x
```
```

But, if we use `curry`, we can make it so that we can re-use the same definition as `multiply`, but only provide the parameters we want (called `partial application`).

```  ```const {curry} = R
const multiply = curry((x, y) => y * x)
const double = multiply(2) // we're only providing one parameter, of the expected 2
```
```

😱 See what we did there?

I'll show it again, but with the `map` example from before:

```  ```const doubleList = map(double) // we're only providing one parameter, of the expected 2
console.log(doubleList([1,3,5,7,9])) // [2,6,10,14,18]
```
```

When `map` is curried this way, it's much more valuable, as it allows us to extricate the array from the function which manipulates the array.

### Function Composition

This is where everything becomes the most exciting.

So, let's say you want to do something simple, like take a value, make it JSON-safe, and print it.

```  ```const input = [{name: `Bark Obama`, type: `dog`}, {name: `Henry Hudson`, type: `cat`}, {name: `Slartibartfast`, type: `magrathean`}]
console.log(JSON.stringify(input))
```
```

Now, let's say for arguments sake that we want to be able to deal with any input, not just the great example I wrote above. In order to do that, we must wrap the expression with a function:

```  ```const prettyPrint = (rawArray) => console.log(JSON.stringify(rawArray))
```
```

Those parentheses at the end are the key here, we're essentially saying, all math-like:

```  ```g(f(x))
```
```

"The result of the function g invoked with the result of the function f invoked with the variable x"

So, suppose we're more than delighted with our contrived function for many months, but then our requirements change. Now we need to only look at a single property, instead of the full raw list, before we stringify it.

Using Ramda's handy `prop` function, we can just grab a value if we know the name.

```  ```const {prop} = R
const prettyPrint = (rawArray) => console.log(
JSON.stringify(
map((thing) => prop(`type`, thing), rawArray)
)
)
```
```

So, right away this seems like it doesn't all need to be an arrow function without braces.

```  ```const prettyPrint = (rawArray) => {
const types = map((thing) => {
return prop(`type`, thing)
}, rawArray)
const stringified = JSON.stringify(types)
console.log(stringified)
}
```
```

Here's a secret you maybe already knew / guessed: all of Ramda's functions are curried. This means that we can go way more terse while still being clear:

```  ```const prettyPrint = (rawArray) => {
const getTypes = map(prop(`type`)) // terse but clear!
const rawTypes = getTypes(rawArray)
const stringified = JSON.stringify(rawTypes)
console.log(stringified)
}
```
```

This is an example of the identity closure, which unfortunately you see all the time in JS. The identity function, as we've discussed, is this: `(x) => x`. The identity closure is this:

```  ```const idClosure = (x) => someFunction(x)
```
```

Unless `someFunction` above has an object binding we need to be aware of, we can simply replace `idClosure` above with:

```  ```const idClosure = someFunction
```
```

And the `map(prop('type'))` example above could be termed a curried identity closure. It partially applies parameters until it becomes a unary function.

So, coming back to our example, see how I named that `getTypes` function, but we could have also done (less clearly), by skipping the intermediate definition:

```  ```const rawTypes = map(prop(`type`))(rawArray)
```
```

Getting back to the now (slightly) more complicated math-style equation:

```  ```g(f(e(x)))
```
```

`e` in our case is the once named `getTypes`.

What we can do now is very exciting.

```  ```const prettyPrint = (a) => {
const b = map(prop(`type`))(a)
const c = JSON.stringify(b)
console.log(c)
}
```
```

👆🏿 I've renamed the variables temporarily for clarity. See the way we're saying, take this one input `a`, invoke this function on it, save that as `b`, invoke a function on it, save that as `c`, and then finally, invoke another function on `c`?

```  ```const {pipe} = R
const prettyPrint = pipe(
map(prop(`type`)), // a => b
JSON.stringify, // b => c
console.log
)
```
```

🤔

So, firstly, what does `pipe` do? Pipe composes together unary functions. It takes any number of unary functions and returns a new function: under the hood it joins them together so each new function receives the value from the last function's output. So whenever you see that kind of `g(f(e(x)))` invocation, you should know that you can reformat it as a pipe-style composition.

Secondly, that's very terse, how do we know other than faith how it works?

😁 Let's dive into `trace`, the first useful thing I ever learned in FP. Pretty much anytime you wanna debug JS, one of your go-to tools is the simple `console.log` to print state somewhere. `trace` uses `console.log` to magical curried effect.

```  ```const trace = curry((a, b) => {
console.log(a, b)
return b
})
```
```

Seems straightforward enough. Trace is defined as a curried binary function which prints both of its inputs and only returns the second one. Because it is curried, it lends itself to pipe composition in the most readable of ways:

```  ```const prettyPrint = pipe(
trace(`input`),
map(prop(`type`)),
trace(`types`),
JSON.stringify,
console.log
)
```
```

Coooooool. So now we have this function, `prettyPrint`, and it prints out some stuff based on `type`. That's dope. (And if you think that's exciting, check out the more generic `xtrace` further below.) But two things. One. Right now we end our composition with `console.log`, and as you may know, that means we never get a real value here. If we omit it:

```  ```const stringifyTypes = pipe(
// trace(`input`),
map(prop(`type`)),
// trace(`types`),
JSON.stringify
)
```
```

Now we have a proper unary function! 🎉

But also, Two. What if down the line, your boss comes down and says that we now need a function which can deal with `name` instead of `type`, so I'd like you to just copy this and paste it and change that one string.

Nuh uh.

We keep it DRY in FP land, and for good reason: it aids our equational reasoning. Check it:

```  ```const stringifyProp = curry((property, input) => pipe(
map(prop(property)),
JSON.stringify
)(input))
```
```

"Wow Brekk, cool new function", you say. "Still seems like extra." And again, I say:

NUH UH!

```  ```const stringifyTypes = stringifyProp(`type`)
const stringifyNames = stringifyProp(`name`)
```
```

Seems like we have two brand new functions, but we know 100% about how they work, because they're different morphisms of the same generic function. 💥

##### xtrace

Ok. So. Finally, here's a really cool way you can take `trace` and push it to be more generic, and then provide a way to inspect our data more granularly.

So, master-level excitement, we have the ability (using `Ramda.curry`, but arguably any equivalent function could do the same) to provide "placeholder" arguments to the function (Read more about R.__ here.), which takes the premise of currying and partial application to a whole new level.

```  ```// definition taken from Ramda (issues with destructuring `__` from `R` in the past)
const placeholder = {
[`@@functional/placeholder`]: true
}
const \$__ = placeholder
const xtrace = curry((log, a, lens, b) => {
log(a, lens(b))
return b
})
const trace = xtrace(console.log, \$__, identity, \$__)
```
```

👆🏿 Check it. We generated a generic function which is pure pure AF (`xtrace`) and then we used its definition to redefine our previous `trace` function. Also, see how useful `identity` can be? (`console.log` is a side-effect / side-cause, unless you pass it in to the function itself, as then it is a known-quantity / pure).

Now, if we define a new function, mebbe call it `thread`:

```  ```const thread = xtrace(console.log)
pipe(
)
```
```

Now we have an amazingly helpful function which has the particularly advantageous morph above, but could ostensibly be used to generate any kind of side-effects during a pipe-composition.

✋🏾 It's over!