Functors and Applicatives
in JavaScript???

Let's talk about functions

a → b

Input an a, get out a b

Any input a will map to one output b

Q: When is a function not a function?

A: When it's a method

a, x?, y?, ... → b? c? void?

... something happened inside some object ...

... some side effects happened, maybe affecting state somewhere else?

... and then something returns ... right?

... well, I get the same output for the same input then, right?

Function: Immunize your cat

A function from Cat → Cat

Strictly speaking ...

Function: Immunize your ???

A function from Cat → Cat null → Shit

Digression: A few words about function composition

When you build up a functional pipeline, everybody has to play nice.

capitalize :: String → String

What if there is no element with the ID you input?

    document.getElementById.bind(document)  // String → DOMElement
1
2
3
4
5
 
var capitalize = R.compose(
    R.toUpperCase,           // String → String
    R.prop('textContent'),   // Object → String
    document.getElementById.bind(document)  // String → DOMElement
);

Functor: Immunize your Cat

n.b.: Same function from Cat → Cat

What the Functor

A functor is simply a function that lets you map over the contents of a container.

map :: (a → b) → Functor a → Functor b

So what?

Functor: Here's What--Immunize your ???

n.b.: Same function from Cat → Cat, now null safe!

Maybe Functor

    return this.value == null ? this : new Maybe(fn(this.value));
1
2
3
4
5
6
7
 
function Maybe(x) { 
    if (!(this instanceof Maybe)) { return new Maybe(x); }
    this.value = x;
}
Maybe.prototype.map = function(fn) {
    return this.value == null ? this : new Maybe(fn(this.value));
};

Composing with the Maybe Functor

capitalize :: String → Maybe(String)

    R.map(R.toUpperCase),                        // Maybe(String) → Maybe(String)
1
2
3
4
5
6
 
var capitalize = R.compose(
    R.map(R.toUpperCase),                        // Maybe(String) → Maybe(String)
    R.map(R.prop('textContent')),                // Maybe(Object) → Maybe(String)
    Maybe,                                       // Object → Maybe(Object)
    document.getElementById.bind(document)       // String → DOMElement
);

Some Other Functors

Either

  • Has a value (right) or a message (left)
  •     return this.right == null ? this : new Either(this.left, f(this.right));
    1
    2
    3
    4
    5
    6
    7
    8
     
    function Either(left, right) {
        if (!(this instanceof Either)) { return new Either(left, right); }
        this.left = left;
        this.right = right;
    }
    Either.prototype.map = function(f) {
        return this.right == null ? this : new Either(this.left, f(this.right));
    }

Promise

  • The map operation is then
  • map(add1, Promise(2)); //=> Promise(3)

Validation, IO, Reader, Writer, State, Future, ...

Array is a Functor

map :: (a → b) → [a] → [b]

(Arrays are complected with the notion of iteration.)

Apply

n.b.: Same function from Cat → Cat, yet again!

Apply (Array)

Applies a function (or functions) in a container to a value (or values) in a container.

ap :: [f] → [a] → [f a]

Clear
Run
        return concat(acc, map(fn, vs));
1
2
3
4
5
 
R.ap = curry(function(fns, vs) {
    return foldl(function(acc, fn) {
        return concat(acc, map(fn, vs));
    }, [], fns);
});

Apply (Maybe)

Clear
Run
    return (typeof this.value !== 'function') ? new Maybe(null) : vs.map(this.value);
1
2
3
 
Maybe.prototype.ap = function(vs) {
    return (typeof this.value !== 'function') ? new Maybe(null) : vs.map(this.value);
};

Problem: Matching Strings

hasAbc :: [String] → Boolean

hasAbc

Applicative

Wraps an arbitrary object in a container.

of :: x → [x]

R.of = function(x) {
1
2
3
 
R.of = function(x) {
    return [x];
};

hasAbc, take 2

What we want is a function hasAbc :: [String] → Boolean

Bibliography, Resources, & Further Reading

Hey Underscore, You're Doing It Wrong, Brian Lonsdorf (@drboolean)
Hardcore functional programming in Javascript, Leonardo Crespo
Favoring Curry, Scott Sauyet (@scott_sauyet)
Why Ramda, Scott Sauyet (@scott_sauyet)
Introducing Ramda, Michael Hurley (@buzzdecafe)
The Tao of λ: Applicatives, Ramda style, Michael Hurley (@buzzdecafe)
Fantasy-Land, Brian McKenna (@puffnfresh) et al.
Folktale, robotlolita (@robotlolita)
Ramda.js, Scott Sauyet & Michael Hurley

Illustrations courtesy of J. C. Phillipps (@jcphillipps)

No animals were harmed in the making of this presentation

1 / 81

#