Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
fp:lab06 [2022/03/25 09:30] pdmatei |
fp:lab06 [2022/04/08 12:45] (current) pdmatei |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Lab 06. Datatypes in Scala ====== | + | ====== Lab 06. Polymorphism in Scala ====== |
- | Consider the following implementation of a simple datatypes to encode natural number: | + | This lab will start with the implementations discussed during lecture. Please find the polymorphic trait ''FList[A]'' below: |
<code scala> | <code scala> | ||
- | trait Nat {} | + | trait FList[A]{ // list with elements of type A |
- | case object Zero extends Nat {} | + | def length: Int |
- | case class Succ(n: Nat) extends Nat {} | + | def head: A |
- | + | def tail: FList[A] | |
- | val three = Succ(Succ(Succ(Zero))) | + | def map[B](f: A => B): FList[B] |
+ | // a op (b op (c op acc)) | ||
+ | def foldRight[B](acc: B)(op: (A,B) => B): B | ||
+ | // ((acc op a) op b) op c | ||
+ | def foldLeft[B](acc: B)(op: (B,A) => B): B | ||
+ | |||
+ | def contains(e: A):Boolean = | ||
+ | this.foldRight(false)(_ == e || _) | ||
+ | |||
+ | } | ||
</code> | </code> | ||
- | Write a function which converts a ''Nat'' into an ''Int'': | + | together with the implementations: |
<code scala> | <code scala> | ||
- | def toInt(n: Nat): Int = | + | case class FNil[A]() extends FList[A]{ |
- | n match { | + | override def length: Int = 0 |
- | case Zero => ??? | + | override def head: A = throw new Exception("head on empty list") |
- | case Succ(n) => ??? | + | override def tail: FList[A] = throw new Exception("head on empty list") |
+ | override def map[B](f: A => B): FList[B] = FNil[B] | ||
+ | override def foldRight[B](acc: B)(op: (A,B) => B): B = acc | ||
+ | override def foldLeft[B](acc: B)(op: (B,A) => B): B = acc | ||
+ | } | ||
+ | |||
+ | case class Cons[A](x:A, xs:FList[A]) extends FList[A]{ | ||
+ | override def length = 1 + xs.length | ||
+ | override def head:A = x | ||
+ | override def tail:FList[A] = xs | ||
+ | override def map[B](f: A => B): FList[B] = | ||
+ | Cons(f(x),xs.map(f)) | ||
+ | override def foldRight[B](acc: B)(op: (A,B) => B): B = | ||
+ | op(x, xs.foldRight(acc)(op)) | ||
+ | override def foldLeft[B](acc: B)(op: (B,A) => B): B = | ||
+ | xs.foldLeft(op(acc,x))(op) | ||
} | } | ||
+ | |||
</code> | </code> | ||
+ | |||
+ | Add the following methods in the trait ''FList'' and implement them. **Some methods can be directly implemented in the trait, using ''map'', ''foldRight'', ''foldLeft'' or other functions.** | ||
+ | * Can you figure which ones are best implemented in the trait and which in the case classes? | ||
+ | |||
+ | **6.1.** ''indexOf'' determines the position of a value in the list (starting with 0) | ||
+ | <code scala> | ||
+ | def indexOf(e: A): Int | ||
+ | </code> | ||
+ | |||
+ | **6.2.** ''update'' creates a new list where the given position is modified with a new value: | ||
+ | <code scala> | ||
+ | //Cons(1,Cons(2,Cons(3,FNil()))).update(9,1) = Cons(1,Cons(9,Cons(3,FNil()))) | ||
+ | def update(e: A, pos: Int): FList[A] | ||
+ | </code> | ||
+ | |||
+ | **6.3.** ''append'' concatenates this list to another: | ||
+ | <code scala> | ||
+ | def append(l: FList[A]): FList[A] | ||
+ | </code> | ||
+ | |||
+ | **6.4.** ''reverse'' returns the reversed list: | ||
+ | <code scala> | ||
+ | def reverse: FList[A] | ||
+ | </code> | ||
+ | |||
+ | **6.5.** ''last'' returns the last element of the list: | ||
+ | <code scala> | ||
+ | def last: A | ||
+ | </code> | ||
+ | |||
+ | **6.6.** ''filter'' filters the elements of the list: | ||
+ | <code scala> | ||
+ | def filter(p: A => Boolean): FList[A] | ||
+ | </code> | ||
+ | |||
+ | **6.7.** ''zip'' combines two lists into a list of pairs. If **either** list is larger, the remaining elements are discarded. | ||
+ | <code scala> | ||
+ | // Cons(1,(Cons(2,Cons(3,FNil()))).zip(Cons(true,Cons(false,Cons(true,FNil())))) = | ||
+ | // Cons((1,true),Cons((2,false),Cons((3,true),FNil()))) | ||
+ | def zip[B](l: FList[B]): FList[(A,B)] | ||
+ | </code> | ||
+ | |||
+ | **6.8.** ''insSorted'' inserts an element into a sorted list so that the result is a sorted list. | ||
+ | <code scala> | ||
+ | def insSorted(f: A => Int)(e: A): FList[A] | ||
+ | </code> | ||
+ | |||
+ | **6.9.** ''sortBy'' sorts a list using insertion sort. | ||
+ | <code scala> | ||
+ | def sortBy(f: A => Int): FList[A] | ||
+ | </code> | ||
+ | |||
+ | **6.10 (!)** Implement a method ''pack'' which encodes a sorted list as follows: | ||
+ | <code scala> | ||
+ | [1,1,1,2,3,4,4,5,6].pack = [(1,3),(2,1),(3,1),(4,2),(5,1),(6,1)] | ||
+ | def pack: FList[(A,Int)] | ||
+ | </code> | ||
+ |