2009-12-03

Catamorphism, an exercise by Tony Morris

Tony Morris posted a Scala exercise where the object was to reimplement the Option API using a catamorphism.  An abstract method cata takes two parameters; two predefined instances of the defining class implement the method to return either of them.  The whole API can then be rewritten as applications of that method.  I haven't checked his solution yet, but I've compared mine to Kris Nuttycombe's posted here (and actually nicked one or two more elegant forms from it).

Anyway, here's my version:

trait MyOption[+A] {
  import MyOption._ 

  // single abstract method
  def cata[X] (some: A => X, none: => X): X
  def map[B] (f: A => B) =
    cata(a => some(f(a)), none)
  def flatMap[B] (f: A => MyOption[B]) =
    cata(f, none)
  def getOrElse[AA >: A] (e: => AA) = cata(a => a, e)
  def filter (p: A => Boolean) =
    cata(a => if (p(a)) this else none, this)
  def foreach (f: A => Unit) { cata(f, ()) }
  def isDefined = cata(_ => true, false)
  def isEmpty = cata(_ => false, true)

  // WARNING: not defined for None
  def get = cata(a => a, error("MyOption.none.get"))

  def orElse[AA >: A] (o: MyOption[AA]) =
    cata(_ => this, o)
  def toLeft[X] (right: => X) =
    cata(a => Left(a), Right(right))
  def toRight[X] (left: => X) =
    cata(a => Right(a), Left(left))
  def toList = cata(a => List(a), Nil)
  def iterator =
    cata(a => Iterator(a), Iterator.empty)
}

object MyOption {
  def none[A] = new MyOption[A] {
    def cata[X](s: A => X, n: => X) = n
  }

  def some[A](a: A) = new MyOption[A] {
    def cata[X](s: A => X, n: => X) = s(a)
  }
}

No comments:

Post a Comment