Differences

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

Link to this comparison view

Next revision
Previous revision
fp2023:lab08 [2023/04/25 15:44]
pdmatei created
fp2023:lab08 [2023/04/26 10:38] (current)
pdmatei
Line 1: Line 1:
 ====== Lab 08: Polymorphism ======= ====== Lab 08: Polymorphism =======
  
-===== 8.1. Ad-hoc polymorphism ​=====+===== 8.1. Companion objects and Option ​=====
  
 Consider the following implementation of the type ''​Nat'',​ which you are well-familiar with: Consider the following implementation of the type ''​Nat'',​ which you are well-familiar with:
Line 32: Line 32:
 which can be called simply as: ''​Nat(5)''​. Also, we can ** (2) overload** ''​apply''​ in order to support creating naturals with the call ''​Nat(.)''​ from different other types. which can be called simply as: ''​Nat(5)''​. Also, we can ** (2) overload** ''​apply''​ in order to support creating naturals with the call ''​Nat(.)''​ from different other types.
  
-**8.1.** Create a companion object for ''​Nat''​ and add appropriate apply functions in order to make the expression ''​Nat(1) + Zero + Nat("​2"​)''​ successfully compile and run.+**8.1.1.** Create a companion object for ''​Nat''​ and add appropriate apply functions in order to make the expression ''​Nat(1) + Zero + Nat("​2"​)''​ successfully compile and run. 
 + 
 +**8.1.2.** Define a function that takes a list of integers and converts them to a list of type ''​List[Option[Nat]]''​. If an integer ''​x''​ is positive, it should become a value ''​Some(x)''​. Otherwise it should become ''​None''​. 
 + 
 +<code scala> 
 +def fromList(l: List[Integer]):​ List[Option[Nat]] = ??? 
 +</​code>​ 
 + 
 +**8.1.3.** Define a function which takes a list of ''​Option[Nat]''​ and converts it to ''​Option[List[Nat]]''​. The logic here is that if the list contains at least one ''​None''​ value (hence **some** conversion from integer failed), then the result should be ''​None''​ . Otherwise, it should be a list containing all valid naturals: 
 +<code scala> 
 +def fromOptions(l:​ List[Option[Nat]]):​ Option[List[Nat]] = ??? 
 +</​code>​ 
  
 ===== 8.2. Dictionaries =====  ===== 8.2. Dictionaries ===== 
 +
 +Create a class ''​Dictionary''​ (which mimics Scala'​s ''​Map''​),​ starting from the following template. A map takes as parameter a list of key-value pairs. (Other, more efficient implementations are possible).
 +<code scala>
 +class Dictionary[K,​V](inner:​ List[(K,​V)]) {
 +
 +}
 +</​code>​
 +
 +**8.2.1.** Create a companion object for Dictionary. Create an apply method which creates a dictionary from a list. For now, it's sole purpose is to //hide// from the programmer the usage of the keyword ''​new''​ when creating a new dictionary, but we will use the companion also later on.
 +
 +**8.2.2.** Create and implement member functions ''​+''​ (adds a new key-value pair to the Dictionary),​ ''​contains''​ and ''​containsKey''​. Use higher-order functions. ​
 +
 +**8.2.3.** Implement the method ''​get''​ which retrieves a value iff it exists:
 +<code scala>
 +def get(key: K): Option[V] = ???
 +</​code>​
 +
 +**8.2.4.** Implement the method ''​getOrElse''​ which returns a default value iff a key is non-existent in the map:
 +<code scala>
 +def getOrElse(default:​ V)(key: K): V = ??? 
 +</​code>​
 +
 +**8.2.5.** Implement ''​map''​ as a member function for dictionaries. Think about how should ''​map''​ work over a dictionary.
 +
 +**8.2.6.** In some situations, we would like to use maps that always return the same default value for a non-existent key. For this reason, implement:
 +<code scala>
 +def withDefaultValue(default:​ V): Dictionary[K,​V] = ???
 +</​code> ​
 +In order to implement it, you need to create a new type of dictionary that stores a default value. The easiest way to implement this, is to modify the class ''​Dictionary''​ as follows:
 +<code scala>
 +class Dictionary[K,​V](inner:​ List[(K,​V)],​ default: Option[V]) {
 +
 +}
 +</​code>​
 +if ''​default''​ is ''​None'',​ then the dictionary behaves exactly as before. On the other hand, if ''​default''​ is ''​Value(v)'',​ then the method ''​get''​ will return the default value. **Careful:​** The function ''​map''​ should also modify the default value!
 +
 +**8.2.7.** Modify the companion object of ''​Dictionary''​ such that the class constructor is concealed: define two apply methods, one for no default value, and one for dictionaries with a given default value. ​
 +
 +===== 8.3. Polynomials =====
 +
 +In this section, we can resort to the datatype ''​Map''​ instead of your previously-defined ''​Dictionary''​.
 +
 +Consider a polynomial encoded as a map, where each present key denotes a power of X, and a value denotes its coefficient. ​
 +<code scala>
 +Map(2 -> 2, 0 -> 3) // encodes 2*X^2 + 3 
 +</​code>​
 +
 +Add to your worksheet, the definition below:
 +<code scala>
 +case class Polynomial (nonZeroTerms:​ Map[Int,​Int]) ​
 +</​code>​
 +
 +**8.3.1.** Add a method ''​*''​ which multiplies the polynomial by a given coeficient:
 +<code scala>
 +def *(n: Int): Polynomial = ???
 +</​code>​
 +
 +**8.3.2.** Override the ''​toString''​ method to nicely display a polynomial. The output should be ordered from the highest-ranking polynomial, and terms with the zero-coeficient should not be displayed.
 +<code scala>
 +override def toString: String = ???
 +</​code>​
 +
 +**8.3.3.** Implement a method ''​hasRoot''​ which checks if a given integer is a root of the polynomial.
 +<code scala>
 +def hasRoot(r: Int): Boolean = ???
 +</​code>​
 +
 +**8.3.4.** Implement a method ''​degree''​ which returns the degree of the polynomial.
 +def degree: Int = ???
 +</​code>​
 +
 +**8.2.5.** Implement a method ''​+''​ which adds a given polynomial to this one. Hint - you can use zip, but other efficient options are possible.
 +<code scala>
 +def +(p2: Polynomial):​ Polynomial = ???
 +</​code>​
 +
 +**8.2.6.** Implement a method ''​*''​ which multiplies polynomials. Hint: this operation is very similar to cartesian product.
 +<code scala>
 +def *(p2: Polynomial):​ Polynomial = ???
 +</​code>​