Recursion

Due: Monday, Sep 22 11:59PM

This assigment has several independent exercises that will develop your grasp of recursion, generics, and higher-order functions.

Preliminaries

Get the software update:

sudo apt-get update
sudo apt-get upgrade cs220
sudo docker.io pull arjunguha/cs220

You may neeed to restart the virtual machine.

Save your work in a file called recursion.scala.

Start your program with these lines:

import cmpsci220._
import cmpsci220.hw.recursion._

The latter line imports the types and some useful functions that you will use in this assignment.

Part 1. Lists

Write the map2 function, which maps over two lists:

def map2[A,B,C](f: (A, B) => C, lst1: List[A], lst2: List[B]): List[C]

test("map2 with add") {
  def add(x: Int, y: Int): Int = x + y
  assert(map2(add, List(1, 2, 3), List(4, 5, 6)) == List(5, 7, 9))
}

You may assume that lst1 and lst2 have the same length (i.e., do whatever you think is reasonable).

Write the zip function, which pairs corresponding elements in a list:

def zip[A,B](lst1: List[A], lst2: List[B]): List[(A, B)]

test("zip test") {
  assert(zip(List(1, 2, 3), List(4, 5, 6)) == List((1,4), (2, 5), (3, 6)))
}

Hint: You can write zip using map2.

Write the function flatten, which flattens a nested list:

def flatten[A](lst: List[List[A]]): List[A]

test("flatten test") {
  assert(flatten(List(List(1, 2), List(3, 4))) == List(1, 2, 3, 4))
}

Hint: You need to write another function before you can write flatten.

Write the flatten3 function, which flattens a triple-nested list:

def flatten3[A](lst: List[List[List[A]]]): List[A]

Hint You can write flatten3 using flatten.

Write the buildList function, which builds a list of the given length. Each element is determined by applying f to the index of the element:

def buildList[A](length: Int, f: Int => A): List[A]

test("buildList test") {
  def f(x: Int) = x
  assert(buildList(10, f) == List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9))
}

Hint: You need to write a helper function.

Write the mapList function, which maps each element to a list and returns the list of all results:

def mapList[A, B](lst: List[A], f: A => List[B]): List[B]

test("mapList test") {
  def f(n: Int): List[Int] = buildList(n, (_: Int) => n)
  assert(mapList(List(1, 2, 3), f) == List(1, 2, 2, 3, 3, 3))
}

Can you write mapList without directly using recursion? i.e., just using the other functions defined above? (You actually can.)

Check Your Work: From the command-line, run:

check220 check recursion step1

Part 2. Persistent Queues

Recall from earlier classes, that a queue is a data structure that supports three operations:

In the following exercises, you will build a persistent queue. A persistent queue has the operations defined. But, instead of having enqueue and dequeue update the queue, they leave the original queue unchanged and return a new queue.

It is easy to implement a persistent queue using a list:

type SlowQueue[A] = List[A]

def emptySlow[A](): SlowQueue[A] = Empty()

def enqueueSlow[A](elt: A, q: SlowQueue[A]): SlowQueue[A] = q match {
  case Empty() => List(elt)
  case Cons(head, tail) => Cons(head, enqueueSlow(elt, tail))
}

def dequeueSlow[A](q: SlowQueue[A]): Option[(A, SlowQueue[A])] = q match {
  case Empty() => None()
  case Cons(head, tail) => Some((head, tail))
}

Read the code above carefully. The enqueue operation traverses the entire list each time (i.e., O(n) running time). Your task is to implement the queue more efficiently.

The trick is to represent the queue using two lists. The first list, called front, has the elements at the front of the queue. The second list, called back, has the elements at the back of the queue, in reverse order.

For example, if front is List(1, 2, 3) and back is List(6, 5, 4), then the elements of the queue, in order, are 1, 2, 3, 4, 5, 6. With this representation:

The cmpsci220.hw.recursion library defines a type called Queue, which has two front and back. Using this type, define the following functions:

def enqueue[A](elt: A, q: Queue[A]): Queue[A]

def dequeue[A](q: Queue[A]): Option[(A, Queue[A])]

Hint: dequeue needs the reverse function, which is defined in the cmpsci220 package.

Check Your Work: From the command-line, run:

check220 check recursion final

Hand In

From the command-line, run the following command:

check220 tar recursion final