Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MyList - step 4

Foreach, Map and Filter

Exercise

Add the following methods to MyList

  • foreach
  • map
  • filter
trait MyList[A]:
  ...
  def foreach(f: A => B): Unit
  def map[B](f: A => B): MyList[B]
  def filter(f: A => Boolean): MyList[A]

Solution Foreach

Empty

override def foreach(f: A => Unit): Unit = ()

Should return Unit. The implementation of Unit is ()

Cons

override def foreach(f: A => Unit): Unit =
  f(head)
  tail.foreach(f)

We have to walk through the linked list get the call the function on the head
and then jump to the tail recursively.

Solution Map

Empty

override def map[B](f: A => B): MyList[B] = Empty[B]()

Transforming an empty list of type A gives us an empty list of type B. This feels a weird. That because of our definition Empty If we had it defined as: case object Empty extends MyList[Nothing]

But then we have implement a covariant/contravariant version op the type A. That is something for the advanced course.

You could leave out the type on the Cons because the compiler know the type from the return type MyList[B] Empty()

Cons

override def map[B](f: A => B): MyList[B] = 
  Cons[B](f(head), tail.map(f))

We have to walk through the linked list of type A
call the function on the head
and walk the tail recursively. And wrap inside a new Cons of type B

You could leave out the type on the Cons because the compiler know the type from the return type MyList[B] Cons(f(head), tail.map(f))

Solution Filter

Empty

override def filter[B](f: A => Boolean): MyList[A] = this

Filtering an empty list gives an empty list.

Cons

override def filter[B](f: A => Boolean): MyList[A] =
  if !f(head) then 
    tail.filter(f)
  else 
    Cons(head, tail.filter(f))

We check if the predicate f on the head is false then we go further on filtering the tail If the predicate f is true then the head is added to new Cons, and then we go further on the filtering the tail

main

@main
def main(): Unit =
  val myList: MyList[Int] = MyList(1,2,3)

  myList.foreach(x => println(x + 2))
  println(myList.map(x => x * 2))
  println(myList.filter(x => x < 2))

// 3
// 4
// 5
// MyList(2, 4, 6)
// MyList(1)