Option Monad in Scala

August 14, 2014

Given a trait Option and two implementations:

sealed trait Option[A] {

  def map[B](f: A => B): Option[B] = ???

  def flatMap[B](f: A => Option[B]): Option[B] = ???

  override def toString(): String =
    this match {
      case Some(a) => "Some(" + a + ")"
      case None()  => "None()"
    }
}

case class Some[A](a: A) extends Option[A]
case class None[A]() extends Option[A]

Implement map and flatMap so that we can use Option in a for-comprehension:

def quotient(divisor: Int)(dividend: Int): Int =
  dividend / divisor

def remainder(divisor: Int)(dividend: Int): Option[Int] =
  (dividend % divisor) match {
    case 0 => None()
    case r => Some(r)
  }

val x3 =
  for {
    x <- Some(42)
    q  = quotient(2)(x)
    r <- remainder(4)(x)
  } yield (x,q,r)

println(x3) // Some((42,21,2))

Solution

Here is one possible solution.
sealed trait Option[A] {

  def map[B](f: A => B): Option[B] =
    this match {
      case Some(a) => Some(f(a))
      case None()  => None()
    }

  def flatMap[B](f: A => Option[B]): Option[B] =
    this match {
      case Some(a) => f(a)
      case None()  => None()
    }

  override def toString(): String =
    this match {
      case Some(a) => "Some(" + a + ")"
      case None()  => "None()"
    }
}

case class Some[A](a: A) extends Option[A]
case class None[A]() extends Option[A]

Demo

This file is literate Scala, and can be run using Codedown:

$ curl https://earldouglas.com/exercises/scala-option.md |
  codedown scala |
  xargs -0 scala -nc -e
Some((42,21,2))