This is an old revision of the document!
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 prettyPrint(tree: BinaryTree, depth: Int): String = { tree match { case TVoid =>"\t" * (depth + 1) + tree.toString() + "\n" case Node(l, value, r) => "\t" * (depth + 1) + value.toString() + "\n" + prettyPrint(l, depth+1) + prettyPrint(r, depth+1) } } prettyPrint(this, 0) } }
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] = ???