Disclaimer: this is a part of a homework assignment.
I want to implement the flatMap for the custom List object. I have successfully implemented map, but I have problem with flatMap. I do not know how to flatten the List of Lists that I get from map. I do not know if I really should use map at all.
trait List[+A] {
/** The first element */
def head: A
/** The rest of the elements */
def tail: List[A]
def flatMap[B](f: A => List[B]): List[B]
def map[B](f: A => B): List[B]
// Concatenate two lists
def concat[B >: A](that: List[B]): List[B] = this match {
case Empty => that
case NonEmpty(head, tail) => NonEmpty(head, tail concat that)
}
}
case object Empty extends List[Nothing] {
def head = throw new UnsupportedOperationException("Empty.head")
def tail = throw new UnsupportedOperationException("Empty.tail")
def flatMap[B](f: Nothing => List[B]): List[B] = Empty
def map[B](f: Nothing => B): List[B] = Empty
override def toString = "Empty"
}
case class NonEmpty[A](head: A, tail: List[A]) extends List[A] {
def map[B](f: A => B): List[B] = {
NonEmpty(f(head), tail.map(f))
}
def flatMap[B](f: A => List[B]): List[B] = {
val a = this.map(f)
for (x <- a; y <- x) yield y
}
}
You have to write flatMap for a list with length n. Try to solve it supposing that you have already solved it for a list with length n-1. If you can do this, then you solved the problem, because n => n-1 => … => 1 => 0, and for 0 you already has a solution.
This kind of thinking is suitable for your List, because it is a recursive type.
You did this already with map, do the same with flatMap. Both function is a transformation from List[A] to List[B], the only difference is the tool what they can use, map has a function that converts A to B, while flatMap has a function that converts A to List[B]