====== Lab 3. Algebraic Datatype Definition ======
===== 3.1 Abstract Lists =====
Below, you will find the algebraic definition of the datatype ''IList'':
Void : IList
Cons : Int x IList -> IList
This definition has already been implemented in Scala, as shown below. Please copy-paste this definition in your worksheet.
trait IList
case object Void extends IList
case class Cons(x: Int, xs: IList) extends IList
**3.1.1.** Consider the following axioms for the operator ''isEmpty''.
isEmpty : IList -> Boolean
isEmpty(Void) = true
isEmpty(Cons(h,t)) = false.
Implement ''isEmpty'' in Scala:
''! Hint:'' To pattern match the list l as a Void or a Cons use the keyword ''match'' from Scala :
def isEmpty(l: IList) : Boolean = {
l match {
case Void => ???
case Cons(x, xs) => ???
}
}
**3.1.2.** Write down axioms for ''size : IList -> Int'' and implement the operator in Scala:
def size(l: IList) : Int = ???
**3.1.3.** Implement ''contains'' to check if an element is a member of a list.
def contains(e: Int, l: IList) : Boolean = ???
**3.1.4.** Implement ''max'' which returns the largest integer from a list:
def max(l: IList) : Int = ???
**3.1.5.** Implement ''take'' which returns a new list containing the first ''n'' elements of the original list:
def take(n: Int)(l: IList) : IList = ???
**3.1.6.** Implement ''drop'' which returns a new list containing the original list without the first ''n'' elements:
def drop(n: Int)(l: IList) : IList = ???
**3.1.7.** Implement ''append'' which concatenates two lists:
def append(l1: IList, l2: IList) : IList = ???
**3.1.8.** (!) Implement ''last'' which returns the last element from a list:
def last(l: IList) : Int = ???
**3.1.9.** (!) 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 = ???
**3.1.10.** Implement ''isSorted'' which checks if a list is sorted:
def isSorted(l: IList) : Boolean = ???
**3.1.11.** Implement ''merge'' which merges two sorted lists:
def merge(l1: IList, l2: IList) : IList = ???
**3.1.12.** Implement ''mergeSort'' which sorts a list:
def mergesort(l: IList) : IList = ???
===== 3.2 Binary Tree =====
The type definition for Scala is given below. Please copy-paste this definition in your worksheet.
trait BinaryTree {
override def toString: String = super.toString: String
}
case object TVoid extends BinaryTree {
override def toString: String = "-"
}
case class Node(left: BinaryTree, info: Int, right: BinaryTree) extends BinaryTree {
override def toString: String = {
def printTree(
tree: BinaryTree,
prefix: String = "",
isLeft: Boolean = true
): String =
tree match {
case TVoid =>
""
case Node(l, value, r) =>
val rightStr =
printTree(r, prefix + (if (isLeft && prefix.nonEmpty) "│ " else " "), isLeft = false)
val nodeStr =
prefix + (if (tree != this) if (isLeft) "└── " else "┌── " else " ") + value.toString + "\n"
val leftStr =
printTree(l, prefix + (if (isLeft) " " else "│ "))
rightStr + nodeStr + leftStr
}
'\n' + printTree(this)
}
}
A Binary Tree can either be a TVoid object (equivalent to NULL in C), or a Node with its information as an Int and two other trees as children (left and right).
**3.2.0.** Implement ''leaf_node'' that receives an Int and returns a leaf with that integer as the node's value:
def leaf_node(value : Int) : BinaryTree = ???
Being given the following BinaryTree:
val arborica = Node(Node(leaf_node(-1), 5, TVoid), 1, Node(leaf_node(4), 2, Node(leaf_node(3), 6, leaf_node(7))))
Implement the following methods for trees in Scala:
**3.2.1.** Implement ''mirror'' that mirrors the tree structure:
def mirror(tree: BinaryTree) : BinaryTree = ???
**3.2.1.** Implement ''flatten'' that squashes the tree traversed in preorder into a list:
def flatten(tree: BinaryTree): List[Int] = ???
**3.2.2.** Define the function ''tmap'' which is the Tree a correspondent to map::(a→b) → [a] → [b].
def tmap(f: Int => Int, tree: BinaryTree) : BinaryTree = ???
**3.2.3.** ! Define the function ''tfoldr'', equivalent of foldr for trees: foldr :: (a -> b -> b) -> b -> Tree a -> b
def tfoldr[B](f: (Int, B) => B, acc: B, tree: BinaryTree): B = ???
**3.2.4.** ! Implement the ''flattening'' function using tfoldr. The order of squashing the tree does not necessarily need to match the previous exercise:
def flattening(tree: BinaryTree): List[Int] = ???