====== 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 binary tree type definition for Scala is given below. Please copy-paste this definition in your Main.scala file from your laboratory project, in order for printTree to work properly. Call print from the function main and click the "run" text above the definition of main to see the result in terminal.
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] = ???