?

  • A monad is a design pattern
  • Values are “wrapped” in a “context”
  • Uses
    • When a computation needs to store side effects (context: side effects). e.g. including a log with a function application
    • “Maybe” types, when the type can either contain a value, or null (context: whether the value is null)
    • Lists, in the view where each element in the list is a choice. Applying the function on first element is choosing the first element, etc. flatMap takes the lists of results and combines them (context: choices)
    • Async operations, monads help to structure the code to be easier to read/write. (context: whether the operation has been completed)
    • etc.
  • Makes code easier to read/write/understand
  • Allows for “side effects” while keeping code purely functional

Definition

  • Informally, a monad design will have these functions
    • flatMap: A function that
      • Takes another function that takes in an “unwrapped” value, and returns a “wrapped” value, after applying an operation
      • Unwraps the current object, and applies the input function to it, then consolidates the results into a wrapped value
      • M<T> -> (T -> M<U>) -> M<U>
      • Takes a wrapped gift, and instructions to create another wrapped gift from the first gifts contents. Unwraps the first gift, then follows the instructions to create a second gift.
    • unit/of: A function that takes in an “unwrapped” value, and wraps it, without additional context
  • Formally, where Monad is a type that is a monad, and monad is an instance of the type:
    • Left identity: Monad.of(a).flatMap(x -> f(x)) == f(a)
    • Right identity: monad.flatMap(x -> Monad.of(x)) == monad
    • Associative: monad.flatMap(x -> f(x)).flatMap(x -> g(x)) == monad.flatMap(x -> f(x).flatMap(y -> g(x)))