====== Lab 06. Polymorphism in Scala ======
This lab will start with the implementations discussed during lecture. Please find the polymorphic trait ''FList[A]'' below:
trait FList[A]{ // list with elements of type A
def length: Int
def head: A
def tail: FList[A]
def map[B](f: A => B): FList[B]
// a op (b op (c op acc))
def foldRight[B](acc: B)(op: (A,B) => B): B
// ((acc op a) op b) op c
def foldLeft[B](acc: B)(op: (B,A) => B): B
def contains(e: A):Boolean =
this.foldRight(false)(_ == e || _)
}
together with the implementations:
case class FNil[A]() extends FList[A]{
override def length: Int = 0
override def head: A = throw new Exception("head on empty list")
override def tail: FList[A] = throw new Exception("head on empty list")
override def map[B](f: A => B): FList[B] = FNil[B]
override def foldRight[B](acc: B)(op: (A,B) => B): B = acc
override def foldLeft[B](acc: B)(op: (B,A) => B): B = acc
}
case class Cons[A](x:A, xs:FList[A]) extends FList[A]{
override def length = 1 + xs.length
override def head:A = x
override def tail:FList[A] = xs
override def map[B](f: A => B): FList[B] =
Cons(f(x),xs.map(f))
override def foldRight[B](acc: B)(op: (A,B) => B): B =
op(x, xs.foldRight(acc)(op))
override def foldLeft[B](acc: B)(op: (B,A) => B): B =
xs.foldLeft(op(acc,x))(op)
}
Add the following methods in the trait ''FList'' and implement them. **Some methods can be directly implemented in the trait, using ''map'', ''foldRight'', ''foldLeft'' or other functions.**
* Can you figure which ones are best implemented in the trait and which in the case classes?
**6.1.** ''indexOf'' determines the position of a value in the list (starting with 0)
def indexOf(e: A): Int
**6.2.** ''update'' creates a new list where the given position is modified with a new value:
//Cons(1,Cons(2,Cons(3,FNil()))).update(9,1) = Cons(1,Cons(9,Cons(3,FNil())))
def update(e: A, pos: Int): FList[A]
**6.3.** ''append'' concatenates this list to another:
def append(l: FList[A]): FList[A]
**6.4.** ''reverse'' returns the reversed list:
def reverse: FList[A]
**6.5.** ''last'' returns the last element of the list:
def last: A
**6.6.** ''filter'' filters the elements of the list:
def filter(p: A => Boolean): FList[A]
**6.7.** ''zip'' combines two lists into a list of pairs. If **either** list is larger, the remaining elements are discarded.
// Cons(1,(Cons(2,Cons(3,FNil()))).zip(Cons(true,Cons(false,Cons(true,FNil())))) =
// Cons((1,true),Cons((2,false),Cons((3,true),FNil())))
def zip[B](l: FList[B]): FList[(A,B)]
**6.8.** ''insSorted'' inserts an element into a sorted list so that the result is a sorted list.
def insSorted(f: A => Int)(e: A): FList[A]
**6.9.** ''sortBy'' sorts a list using insertion sort.
def sortBy(f: A => Int): FList[A]
**6.10 (!)** Implement a method ''pack'' which encodes a sorted list as follows:
[1,1,1,2,3,4,4,5,6].pack = [(1,3),(2,1),(3,1),(4,2),(5,1),(6,1)]
def pack: FList[(A,Int)]