Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
pp:2025:scala:l03 [2025/03/13 13:18]
cata_chiru
pp:2025:scala:l03 [2025/03/28 12:04] (current)
cata_chiru
Line 1: Line 1:
 ====== Lab 3. Algebraic Datatype Definition ====== ====== Lab 3. Algebraic Datatype Definition ======
  
-Below you will find the algebraic definition of the datatype ''​IList'':​+===== 3.1 Abstract Lists ===== 
 + 
 +Belowyou will find the algebraic definition of the datatype ''​IList'':​
 <​code>​ <​code>​
 Void : IList Void : IList
Line 7: Line 9:
 </​code>​ </​code>​
  
-This definition has already been implemented in Scala, below. Please copy-paste this definition in your worksheet.+This definition has already been implemented in Scala, ​as shown below. Please copy-paste this definition in your worksheet.
 <code scala> <code scala>
 trait IList  trait IList 
Line 14: Line 16:
 </​code>​ </​code>​
  
-**4.1.** Consider the following axioms for the operator ''​isEmpty''​.+**3.1.1.** Consider the following axioms for the operator ''​isEmpty''​.
 <​code>​ <​code>​
 isEmpty : IList -> Boolean isEmpty : IList -> Boolean
Line 21: Line 23:
 </​code>​ </​code>​
 Implement ''​isEmpty''​ in Scala: Implement ''​isEmpty''​ in Scala:
 +
 +''​! Hint:''​ To pattern match the list l as a Void or a Cons use the keyword ''​match''​ from Scala :
 <code scala> <code scala>
-def isEmpty(l: IList): Boolean = ???+def isEmpty(l: IList) : Boolean = 
 +    l match { 
 +        case Void => ??? 
 +        case Cons(x, xs) => ??? 
 +    } 
 +}
 </​code>​ </​code>​
  
-**4.2.** Write down axioms for ''​size : IList -> Int''​ and implement the operator in Scala:+ 
 +**3.1.2.** Write down axioms for ''​size : IList -> Int''​ and implement the operator in Scala:
 <code scala> <code scala>
-def size(l: IList): Int = ???+def size(l: IList) : Int = ???
 </​code>​ </​code>​
  
-**4.3.** Implement ''​contains'' ​which checks ​if an element is a member of a list.+**3.1.3.** Implement ''​contains'' ​to check if an element is a member of a list.
 <code scala> <code scala>
-def contains(e: Int, l: IList): Boolean = ???+def contains(e: Int, l: IList) : Boolean = ???
 </​code>​ </​code>​
  
-**4.4.** Implement ''​max''​ which returns the largest integer from a list:+**3.1.4.** Implement ''​max''​ which returns the largest integer from a list:
 <code scala> <code scala>
-def max(l: IList): Int = ???+def max(l: IList) : Int = ???
 </​code>​ </​code>​
  
-**4.5.** Implement ''​take''​ which returns a new list containing the first ''​n''​ elements of the original list:+**3.1.5.** Implement ''​take''​ which returns a new list containing the first ''​n''​ elements of the original list:
 <code scala> <code scala>
-def take(n: Int)(l: IList): IList = ???+def take(n: Int)(l: IList) : IList = ???
 </​code>​ </​code>​
  
-**4.6.** Implement ''​drop''​ which returns a new list containing the original list without the first ''​n''​ elements:+**3.1.6.** Implement ''​drop''​ which returns a new list containing the original list without the first ''​n''​ elements:
 <code scala> <code scala>
-def drop(n: Int)(l: IList): IList = ???+def drop(n: Int)(l: IList) : IList = ???
 </​code>​ </​code>​
  
-**4.7.** Implement ''​append''​ which concatenates two lists:+**3.1.7.** Implement ''​append''​ which concatenates two lists:
 <code scala> <code scala>
-def append(l1: IList, l2: IList): IList = ???+def append(l1: IList, l2: IList) : IList = ???
 </​code>​ </​code>​
  
-**4.8.** (!) Implement ''​last''​ which returns the last element from a list:+**3.1.8.** (!) Implement ''​last''​ which returns the last element from a list:
 <code scala> <code scala>
-def last(l: IList): Int = ???+def last(l: IList) : Int = ???
 </​code>​ </​code>​
  
-**4.9.** (!) Implement ''​reverse''​. There are two different ways to implement reverse (with direct and with tail-end recursion). Try both implementations.+**3.1.9.** (!) Implement ''​reverse''​. There are two different ways to implement reverse (with direct and with tail-end recursion). Try both implementations.
 <code scala> <code scala>
-def reverse(l: IList): IList = ???+def reverse(l: IList) : IList = ???
 </​code>​ </​code>​
  
-**4.10.** Implement ''​isSorted''​ which checks if a list is sorted:+**3.1.10.** Implement ''​isSorted''​ which checks if a list is sorted:
 <code scala> <code scala>
-def isSorted(l: IList): Boolean = ???+def isSorted(l: IList) : Boolean = ???
 </​code>​ </​code>​
  
-**4.11.** Implement ''​merge''​ which merges two sorted lists:+**3.1.11.** Implement ''​merge''​ which merges two sorted lists:
 <code scala> <code scala>
-def merge(l1: IList, l2: IList): IList = ???+def merge(l1: IList, l2: IList) : IList = ???
 </​code>​ </​code>​
  
-**4.12.** Implement ''​mergeSort''​ which sorts a list:+**3.1.12.** Implement ''​mergeSort''​ which sorts a list:
 <code scala> <code scala>
-def mergesort(l:​ IList) IList = ???+def mergesort(l:​ IList) ​IList = ???
 </​code>​ </​code>​
 +
 +===== 3.2 Binary Tree =====
 +
 +The type definition for Scala is given below. Please copy-paste this definition in your worksheet.
 +<code scala>
 +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)
 +  }
 +}
 +</​code>​
 +
 +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:
 +<code scala>
 +def leaf_node(value : Int) : BinaryTree = ???
 +</​code>​
 +
 +Being given the following BinaryTree:
 +<code scala>
 +val arborica = Node(Node(leaf_node(-1),​ 5, TVoid), 1, Node(leaf_node(4),​ 2, Node(leaf_node(3),​ 6, leaf_node(7))))
 +</​code>​
 +
 +Implement the following methods for trees in Scala:
 +
 +**3.2.1.** Implement ''​mirror''​ that mirrors the tree structure:
 +<code scala>
 +def mirror(tree:​ BinaryTree) : BinaryTree = ???
 +</​code>​
 +
 +**3.2.1.** Implement ''​flatten''​ that squashes the tree traversed in preorder into a list:
 +<code scala>
 +def flatten(tree:​ BinaryTree):​ List[Int] = ???
 +</​code>​
 +
 +**3.2.2.** Define the function ''​tmap''​ which is the Tree a correspondent to map::​(a→b) → [a] → [b]. 
 +<code scala>
 +def tmap(f: Int => Int, tree: BinaryTree) : BinaryTree = ???
 +</​code>​
 +
 +**3.2.3.** ! Define the function ''​tfoldr'',​ equivalent of foldr for trees: foldr :: (a -> b -> b) -> b -> Tree a -> b
 +<code scala>
 +def tfoldr[B](f:​ (Int, B) => B, acc: B, tree: BinaryTree):​ B = ???
 +</​code>​
 +
 +**3.2.4.** ! Implement the ''​flattening''​ function using tfoldr. The order of squashing the tree does not necessarily need to match the previous exercise: ​
 +<code scala>
 +def flattening(tree:​ BinaryTree):​ List[Int] = ???
 +</​code>​
 +
 +
 +