Back to Fpinscala

01.Answer

answerkey/laziness/01.answer.md

latest1.1 KB
Original Source
scala
// The natural recursive solution
def toListRecursive: List[A] = this match
  case Cons(h,t) => h() :: t().toListRecursive
  case Empty => Nil

/*
The above solution will stack overflow for large lazy lists, since it's
not tail-recursive. Here is a tail-recursive implementation. At each
step we cons onto the front of the `acc` list, which will result in the
reverse of the lazy list. Then at the end we reverse the result to get the
correct order again.
*/
def toList: List[A] =
  @annotation.tailrec
  def go(ll: LazyList[A], acc: List[A]): List[A] = ll match
    case Cons(h, t) => go(t(), h() :: acc)
    case Empty => acc.reverse
  go(this, Nil)

/*
In order to avoid the `reverse` at the end, we could write it using a
mutable list buffer and an explicit loop instead. Note that the mutable
list buffer never escapes our `toList` method, so this function is
still _pure_.
*/
def toListFast: List[A] =
  val buf = new collection.mutable.ListBuffer[A]
  @annotation.tailrec
  def go(ll: LazyList[A]): List[A] = ll match
    case Cons(h, t) =>
      buf += h()
      go(t())
    case Empty => buf.toList
  go(this)