====== 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)]