6 - Monads

Monads, baby!
Today we look at certain kinds of computations from a truly functional perspective:

  • computations that might or might not have a value
  • computations that might fail
  • computations that will finish at some point

But we won't get into math and category theory for this.
We'll see what a monad is from a programming perspective, directly in the Scala language.

You can find today's contents here.


Let's implement some of our own monads.

  1. Let's write a monad equivalent with Option. Let's call this Maybe, as in Haskell.
    • create a trait Maybe[+A] (remember the [A] is equivalent to Java's <A> syntax for generics and ignore the + for now)
    • add some functional primitives as methods to Maybe:
      • the monad requirements: map, flatMap, filter
      • zipWith, which receives a Maybe[B] and returns a Maybe[(A,B)]
        The signature is just a tiny bit more complex:
        def zipWith[B](other: Maybe[B]): Maybe[(A,B)]

        If either this or other is empty, the result will be an empty Maybe.

      • exists, which receives a predicate (a function of A to Boolean) and returns true if this instance contains an element which satisfies the predicate
      • orElse, a special method for Maybe, which returns this instance if it's not empty, or an alternative otherwise; the signature will be
        def orElse[B >: A](alternative: Maybe[B]): Maybe[B]

        (ignore the >: for now)
        How can you delay the computation of the alternative until you actually need it? (hint: call by value/call by name)

    • add some utility methods to the Maybe trait:
      • isEmpty
      • toList
      • size
    • create two case subclasses: Just[A] and Empty and implement the methods
      • what is Empty, actually? a case class? a case object?
      • methods should be quick to write and probably take two lines of code, at most
  2. An equivalent to Scala's Try monad, call this Attempt[A].
    • as before, create a trait Attempt[A] and two case subclasses, Success[A] and Fail
    • Success has a member of type A, Fail has a member of type Throwable
    • add some functional primitives to your Attempt and implement them in the subclasses:
      • map, flatMap, filter
      • zipWith
      • exists
      • isEmpty, toList, size
      • a special method - recoverWith; the method returns an alternative Attempt computation if this one fails
  3. Talk about the Future[T] (pun intended) if you finish early!
sesiuni/scala/lab6.txt · Last modified: 2016/07/04 20:07 by dciocirlan