Andrew (he/him)

Posted on

# (Kinda sloppy) Monad-based Options in Scala

Worked on this one for a while today. What do you think? What would you change?

There's a bit of a tradeoff between making the type parameters a bit "cleaner" vs. the same for the method signatures in the Option... I'm not sure which way to go with it.

trait Functor[+A, F[_]] {
def map[B](f: A => B): F[B]
}

trait Monad[+A, F[_]] extends Functor[A, F] {
def unit[X](a: => X): F[X]
def flatMap[B](f: A => F[B]): F[B]
def map[B](f: A => B): F[B] = flatMap(a => unit(f(a)))
def flatten[B](implicit ev: A <:< F[B]): F[B] = flatMap[B](identity[A])
}

sealed trait Option[+T] extends Monad[T, Option] {
import Option._
override def unit[X](a: => X): Option[X] = Some(a)
override def flatMap[B](f: T => Option[B]): Option[B] = this match {
case Some(x) => f(x)
case None => None
}
}

object Option {
case class Some[T](x: T) extends Option[T]
case object None extends Option[Nothing]
}

import Option._
val somePinned: Option[Int] = Some(42)
val nonePinned: Option[Int] = None

println(somePinned.map(_ * 2))          // Some(42)
println(nonePinned.map(_ * 2))          // None
println(Some(Some(42)))                 // Some(Some(42))
println(Some(Some(42)).flatMap(x => x)) // Some(42)
println(Some(Some(42)).flatten)         // Some(42)
}