====== Lab 4. Algebraic Datatype definition ====== Consider the following type defined to represent lists of integers: trait IList case object Void extends IList case class Cons(x: Int, xs: IList) extends IList **4.1.** Implement ''isEmpty'' which checks if a list is empty: def isEmpty(l: IList): Boolean = ??? **4.2.** Implement ''size'' which returns the size of the list: def size(l: IList): Int = ??? **4.3.** Implement ''append'' which concatenates two lists: def append(l1: IList, l2: IList): IList = ??? **4.4.** (!) Implement ''last'' which returns the last element from a list: def last(l: IList): Int = ??? **4.5.** (!) Implement ''reverse''. There are two different ways to implement reverse (with direct and with tail-end recursion). Try both implementations. def reverse(l: IList): IList = ??? **4.6.** Implement ''contains'' which checks if an element is a member of a list. def contains(e: Int, l: IList): Boolean = ??? **4.7.** Implement ''max'' which returns the largest integer from a list: def max(l: IList): Int = ??? **4.8.** Implement ''take'' which returns a new list containing the first ''n'' elements of the original list: def take(n: Int)(l: IList): IList = ??? **4.9.** Implement ''drop'' which returns a new list containing the original list without the first ''n'' elements: def drop(n: Int)(l: IList): IList = ??? **4.10.** Implement ''isSorted'' which checks if a list is sorted: def isSorted(l: IList): Boolean = ??? **4.11.** Implement ''merge'' which merges two sorted lists: def merge(l1: IList, l2: IList): IList = ??? **4.12.** Implement ''mergeSort'' which sorts a list: def mergesort(l: IList) IList = ???