Skip to content

Functors and Monads (and Optional)

Cheng Yu Feng edited this page Nov 29, 2020 · 3 revisions

Functors

A functor should have:

  • private T thing: a payload
  • make(U thing): a constructor, usually a static method
  • map(Function<? super T, ? extends U> f): transforms the payload, returns the transformed payload in a new Functor

An abstract Functor would be as follows:

abstract class Functor<T> {
    private T thing;
    abstract public <U> Functor<U> foo(Function<? super T, ? extends U> func);
}

Functors should satisfy two laws:

  • identity: make(t).map(x -> x).equals(make(t))
  • associativity: make(t).map(f).map(g).equals(make(t).map(f.andThen(g)))

Monads

A monad should have:

  • private T thing: a payload
  • make(U thing): a constructor, usually a static method
  • flatmap(Function<? super T, ? extends Monad<? extends U>> func)

flatmap helps us return a Monad<? extends U> instead of Monad<Monad<? extends U>>, avoiding nesting.

An abstract Monad would be as follows:

abstract class Monad<T> {
    private T thing;
    public <U> Monad<U> bar(Function<? super T, ? extends Monad<? extends U>> func);
}

Monads should satisfy three laws:

  • left identity: make(t).flatmap(f).equals(f(t))
  • right identity: make(t).flatmap(x -> make(x)).equals(make(t))
  • associativity: make(t).flatMap(f).flatMap(g).equals(make(t).flatmap(f.andThen(g))).

Optional<T>

Is both a Functor and a Monad.

Several useful methods in Optional<T>:

  • ofNullable(T thing): constructor
  • filter, flatmap, map
  • ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
  • for running actions with void return types.
  • or, orElse, orElseGet, orElseThrow
  • or(Supplier<? extends Optional<? extends T>> s): returns the Optional from s.get().
  • orElse(T thing): returns thing, which is eagerly evaluated, unlike or and orElseGet which take in Suppliers.
  • orElseGet(Supplier<? extends T> supplier): returns type T thing lazily, unlike orElse.
  • orElseThrow
    • no parameter provided: throws NoSuchElementException
    • Supplier<? extends Exception> provided: throws the exception in the parameter.

Avoid: get(), isEmpty(), isPresent(), to adhere to the functional programming paradigm.

Clone this wiki locally