Functors & Monads
WTF FTW

  1. Motivation
  2. Containers
  3. Functors
  4. Maybe/Option
  5. Applicative Functors
  6. Monads

Motivation

FP: Compose programs of pure functions.

  • Easy to reason about,
  • reuse,
  • refactor,
  • test.

                // imperative
                let makes = [];
                for (let i = 0; i < cars.length; i++) {
                    if (car.ready) {
                        makes.push(cars[i].make);
                    }
                }
            

                // declarative
                const makes = cars
                    .filter(car => car.ready)
                    .map(car => car.make);
            

                // imperative
                let makes = [];
                for (let i = 0; i < cars.length; i++) {
                    if (car.ready) {
                        makes.push(cars[[i].make);
                    }
                }
            

                // declarative
                const makes = cars
                    .filter(car => car.ready)
                    .map(car => car.make);
            

What about control flow, error handling, async & side effects?

Use containers, functors, applicative functors & monads.

Container

Container in JavaScript


                    const Container = function(x) {
                      this.__value = x;
                    };

                    Container.of = x => new Container(x);
                

Container in Java


                    class Container {
                        private T value;

                        public static  Container of(T value) {
                            return new Container<>(value);
                        }

                        private Container(T value) {
                            this.value = value;
                        }
                    }
                
What?

Container ≙ io.vavr.Value


                    package io.vavr;

                    public interface Value {
                        T get();
                        T getOrElse(T other);
                        /* …je suis immutable… */
                    }
                

                    public interface Option extends Value { /* … */ }
                    public interface Future extends Value { /* … */ }
                    public interface Try extends Value { /* … */ }
                    public interface Either extends Value { /* … */ }
                    public interface Validation extends Value { /* … */ }
                

Functors

Definition of Functor from Wikipedia
That's a lovely accent you have… New Jersey?

A Functor is a type that implements map and obeys some laws.

We could have just as easily named it Mappable.

Functor in JavaScript


                    // get :: Container c => c a ~> a
                    Container.prototype.get = function() {
                        return this.__value;
                    }

                    
                    // map :: Container c => c a ~> (a -> b) -> c b
                    Container.prototype.map = function(f) {
                        return Container.of(f(this.__value))
                    }
                    
                

                    Container.of('foo')
                        .map(x => x + 'bar')
                        .map(x => x.toUppercase)
                        .get();
                    // 'FOOBAR'
                

Functor in Java



                    <U> Container<U> map(Function mapper) {
                        return Container.of(mapper.apply(value));
                    }
                

                    String result = Container.of("foo")
                        .map(x -> x + "bar")
                        .map(String::toUpperCase)
                        .get();
                
Boring

Maybe/Option

Option is a monadic container type which represents an optional value. Instances of Option are either an instance of Some or the None.

Schrödinger's cat

Option in vavr


                    public interface Option<T> extends Value<T>, Serializable {

                        default <U> Option<U> map(Function<? super T, ? extends U> mapper) {
                            return isEmpty()
                                ? none()
                                : some(mapper.apply(get()));
                        }

                    }
                

                    final class Some<T> implements Option<T>, Serializable {
                        public boolean isEmpty() { return false; }
                    }

                    final class None<T> implements Option<T>, Serializable {
                        public boolean isEmpty() { return true; }
                    }
                

vavr Option


                    class Foo {
                        public static Option<String> getBar() { /* … */ }
                    }

                    String bar = Foo.getBar()
                        .map(String::toUpperCase)
                        .getOrElse("BAR");
                

Option in vavr


                    public interface Option<T> extends Value<T>, Serializable {

                        default <U> Option<U> flatMap(Function<? super T, ? extends Option<? extends U>> mapper) {
                            return isEmpty() ? none() : (Option<U>) mapper.apply(get());
                        }

                    }
                

                    class Foo {
                        public static Option<String> getBar() { /* … */ }
                    }

                    String bar = Foo.getBar()
                        .flatMap(bar ->
                            bar.equals('empty')
                                ? Option.none()
                                ? Option.some(bar)
                        )
                        .map(String::toUpperCase)
                        .getOrElse("BAR");
                

Applicative Functors

Monads

Links