Exercise: Collecting transformations in Scala

September 07, 2017

Given a list of numbers and a function that (noisily) increments a number:

val list: List[Int] = (1 to 100).toList

def inc(x: Int): Int = {
  val y: Int = x + 1
  println(s"inc($x) = $y")
  y
}

Observe that mapping the function over the list produces a lot of noise, because List eagerly applies transformations:

val mappedList: List[Int] = list map inc map inc map inc
inc(0) = 1
inc(1) = 2
...
inc(99) = 100
inc(100) = 101
inc(2) = 3
inc(3) = 4
...
inc(100) = 101
inc(101) = 102
inc(3) = 4
inc(4) = 5
...
inc(101) = 102
inc(102) = 103

Implement a lazy linked list called Stream and a Functor instance that defers map transformations until take is applied:

sealed trait Stream[+A] {
  def take(n: Int): List[A]
}
trait Functor[F[_]] {
  def map[A,B](fa: F[A])(f: A => B): F[B]
}

implicit class FunctorOps[A,F[_]:Functor](fa: F[A]) {
  def map[B](f: A => B): F[B] =
    implicitly[Functor[F]].map(fa)(f)
}