Lab 4. Functional vs Object-Oriented decomposition

4.1. The type Nat

Consider the following type defined to represent natural numbers:

trait Nat {
   def isZero: Boolean
   def add(other: Nat): Nat
   def subtract(other: Nat): Nat
   def greater(other: Nat): Boolean
   def toInt: Int
}
case object Zero extends Nat
case class Succ(n: Nat) extends Nat

When implementing the following methods, think about whether or not they are local (are they best implemented using functional or OO decomposition?)

4.1.1. Implement the method isZero which checks if a number is equal to Zero or not.

4.1.2. Implement the addition method over natural numbers.

4.1.3. Implement the subtraction method over natural numbers. If $ n > m$ then $ m - n = 0$ .

4.1.4. Implement greater which checks if a natural number is strictly larger than the other.

4.1.5. Implement a function which converts a Nat to a Scala Int.

4.2. The type OList (Object-Oriented implementation of lists)

Start with the following trait, which encodes lists over integers.

trait OList{
  def head: Int 
  def tail: OList
  def foldRight[B](acc: B)(op: (Int,B) => B): B
  def foldLeft[B](acc: B)(op: (B,Int) => B): B
  def indexOf(i: Int): Int
  def filter(p: Int => Boolean): OList
  def map(f: Int => Int): OList
  def partition(p: Int => Boolean): (OList, OList)
  def slice(start: Int, stop: Int): OList
  def forall(p: Int => Boolean): Boolean
}

4.2.1. Implement the constructors for the empty list as well as for the nonempty list of integers.

4.2.2. Implement head and tail accordingly.

4.2.3. Implement foldRight. Follow the same strategy as in the previous labs. Also implement foldLeft. Make sure it is tail-recursive.

4.2.5. Implement filter. Try and use foldRight in your implementation. The following diagram illustrates the behaviour of filter:

   1 2 3 4 5 6 7 8 9 10 11
       filter(p => p % 2 == 0)
     2   4   6   8   10  

4.2.4. Implement indexOf which retrieves the position of an element in a list if it exists and -1 otherwise. Try and use an appropriate type of fold for your implementation.

4.2.6. Implement map. Try and use an appropriate type of fold in your implementation. The following diagram illustrates the behaviour of map:

   1 2 3 4 5  6  7  8  9  10
      map (_*2)
   2 4 6 8 10 12 14 16 18 20

4.2.7. Implement partition. It is supposed to return a pair of lists. (!!) Try and use an appropriate type of fold in your implementation. The following diagram illustrates the behaviour of partition:

   1 2 3 4 5 6 7 8 9 10
     partition(_ % 2 == 0)
(1 3 5 7 9, 2 4 6 8 10)

4.2.8. Implement slice. The following diagram illustrates the behaviour of slice:

   1 2 3 4 5 6 7 8 9 10
     slice(2,4)
   3 4 5

4.2.8. Implement forall. Try and use an appropriate type of fold in your implementation. The following diagram illustrates the behaviour of forall:

   1 2 3 4 5 6 7 8 9 10
     forall(_ % 2 == 0)
     false