answerkey/laziness/13.answer.md
def mapViaUnfold[B](f: A => B): LazyList[B] =
unfold(this):
case Cons(h, t) => Some((f(h()), t()))
case _ => None
def takeViaUnfold(n: Int): LazyList[A] =
unfold((this, n)):
case (Cons(h, t), 1) => Some((h(), (empty, 0)))
case (Cons(h, t), n) if n > 1 => Some((h(), (t(), n-1)))
case _ => None
def takeWhileViaUnfold(f: A => Boolean): LazyList[A] =
unfold(this):
case Cons(h, t) if f(h()) => Some((h(), t()))
case _ => None
def zipAll[B](that: LazyList[B]): LazyList[(Option[A], Option[B])] =
unfold((this, that)):
case (Empty, Empty) => None
case (Cons(h1, t1), Empty) => Some((Some(h1()) -> None) -> (t1() -> Empty))
case (Empty, Cons(h2, t2)) => Some((None -> Some(h2())) -> (Empty -> t2()))
case (Cons(h1, t1), Cons(h2, t2)) => Some((Some(h1()) -> Some(h2())) -> (t1() -> t2()))
def zipWith[B,C](that: LazyList[B])(f: (A,B) => C): LazyList[C] =
unfold((this, that)):
case (Cons(h1, t1), Cons(h2, t2)) =>
Some((f(h1(), h2()), (t1(), t2())))
case _ => None
// special case of `zipWith`
def zip[B](that: LazyList[B]): LazyList[(A,B)] =
zipWith(that)((_,_))
def zipWithAll[B, C](that: LazyList[B])(f: (Option[A], Option[B]) => C): LazyList[C] =
LazyList.unfold((this, that)):
case (Empty, Empty) => None
case (Cons(h, t), Empty) => Some(f(Some(h()), Option.empty[B]) -> (t(), empty[B]))
case (Empty, Cons(h, t)) => Some(f(Option.empty[A], Some(h())) -> (empty[A] -> t()))
case (Cons(h1, t1), Cons(h2, t2)) => Some(f(Some(h1()), Some(h2())) -> (t1() -> t2()))
def zipAllViaZipWithAll[B](s2: LazyList[B]): LazyList[(Option[A],Option[B])] =
zipWithAll(s2)((_,_))