====== Lab 11. Polymorphism and For expressions in Scala ======
=== I. Polymorphism ===
This lab will start with the implementations discussed during lecture. Please find the polymorphic trait ''FList[A]'' below:
trait FList[A]{ // list with elements of type A
def length: Int
def head: A
def tail: FList[A]
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 || _)
}
together with the implementations:
case class FNil[A]() extends FList[A]{
override def length: Int = 0
override def head: A = throw new Exception("head on empty list")
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)
}
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?
**1.1.** ''indexOf'' determines the position of a value in the list (starting with 0)
def indexOf(e: A): Int
**1.2.** ''update'' creates a new list where the given position is modified with a new value:
//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]
**1.3.** ''append'' concatenates this list to another:
def append(l: FList[A]): FList[A]
**1.4.** ''reverse'' returns the reversed list:
def reverse: FList[A]
**1.5.** ''last'' returns the last element of the list:
def last: A
**1.6.** ''filter'' filters the elements of the list:
def filter(p: A => Boolean): FList[A]
**1.7.** ''zip'' combines two lists into a list of pairs. If **either** list is larger, the remaining elements are discarded.
// 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)]
**1.8.** ''insSorted'' inserts an element into a sorted list so that the result is a sorted list.
def insSorted(f: A => Int)(e: A): FList[A]
**1.9.** ''sortBy'' sorts a list using insertion sort.
def sortBy(f: A => Int): FList[A]
**1.10 (!)** Implement a method ''pack'' which encodes a sorted list as follows:
[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)]
=== II. For expressions ===
We will use matrices to encode Bitmap images. The format is called BPM, and more details are available [[https://en.wikipedia.org/wiki/Netpbm#File_formats|here]]. Our format will be grayscale only. Each pixel of the matrix is encoded as an integer, with values from 0 to 255. Some examples are shown below:
0 0 1 0 0
0 1 0 1 0
0 1 1 1 0 letter A
1 0 0 0 1
1 0 0 0 1
5 4 3 2 1
5 4 3 2 1
5 4 3 2 1 shader
5 4 3 2 1
5 4 3 2 1
Add the following type definition for the rest of your lab:
type Img = List[List[Int]]
Also, in order to benefit from visualisation, instead of using a worksheet, you can create a new Scala project, containing an object with a main method:
object Matrix {
// define your functions here
def main(args: Array[String]) = {
// write your tests here
}
}
**2.1.** Write a function which converts an image to a string (Hint: you can draw inspiration from a similar one from the lecture):
def show(m: Img): String = ???
**2.2.** Write a function which performs a horizontal flip on an image. Try to first visualise (you may use pen and paper) how the transformation would look like.
def hFlip(img: Img): Img = ???
**2.3.** Write a function which performs vertical flip.
def vFlip(img: Img): Img = ???
**2.4.** Write a function which performs a 90 degrees rotation to the right. (Hint: you need an ingredient from the lecture. Also, note that there are multiple possible implementations.)
def rot90Right(img: Img): Img = ???
**2.5.** Write a function which performs a 90 degrees rotation to the left.
def rot90Left(img: Img): Img = ???
**2.6.** Write a function which inverts an image (values 0 become 255, 1 - 254, and so forth).
**2.7.** Write a function which crops a given image, using two, two-dimensional coordinates: the higher-left point x and y, and the lower-right point x and y. An example is shown below:
val img = List(List(0,0,1,0,0), List(0,1,0,1,0), List(0,1,1,1,0), List(1,0,0,0,1), List(1,0,0,0,1))
/*
0 0 1 0 0
* 0 1 0 1 0 1 0 1
* 0 1 1 1 0 cropping from 1,1 to 2,3 yields: 1 1 1
* 1 0 0 0 1
* 1 0 0 0 1
*/
def cropAt(img: Img, xSt:Int, ySt:Int, xEnd: Int, yEnd: Int): Img = ??
**2.8.** Write a function which returns a list of all positions which have pixels of larger intensity than x
def largerPos(img: Img, int: Int): List[(Int,Int)] = ???
**2.9.** Write a function which adds ''x'' to the intensity of each pixel.
def contrast(x: Int)(img: Img): Img = ???
**2.10.** Write a function which takes two images ''X'' and ''Y'' and //glues// them on the horizontal axis (the resulting image will be ''XY'')
def hglue(img1: Img, img2: Img): Img = ???
**2.11.** Write a function which takes two images ''X'' and ''Y'' and //glues// them on the vertical axis:
def vglue(img1: Img, img2: Img): Img = ???
**2.12.** Define a function that takes a **square** image, and draws two diagonal lines of intensity 1 across it. Use ''_.until(_)'' and ''_.toList''.
def diag(img: Img): Img = ???
**2.13.** Define a function which blurs an image as follows:
* for each pixel p of intensity > 1: make all neighbouring pixels of intensity 0 equal to p-1 (including diagonals).
* if some pixel of intensity 0 is in the vicinity of two different >1 pixels of different intensities, the one which is larger should be taken into account
* to make the implementation easier, you do not need to implement the blur on the image edges.
def blur(img: Img): Img = ???
**2.14. (!) ** Define a function which builds an effect of intensity x as shown below:
val img2 = List(
List(0,0,0,0,0,0,0,0,0),
List(0,0,0,0,0,0,0,0,0),
List(0,0,0,0,0,0,0,0,0),
List(0,0,0,0,1,0,0,0,0),
List(0,0,0,1,2,1,0,0,0),
List(0,0,0,0,1,0,0,0,0),
List(0,0,0,0,0,0,0,0,0),
List(0,0,0,0,0,0,0,0,0),
List(0,0,0,0,0,0,0,0,0)
)
/*
Before: After (for x = 2)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 1 1 2 2 2 1 1 0
0 0 0 0 1 0 0 0 0 0 1 2 2 3 2 2 1 0
0 0 0 1 2 1 0 0 0 0 1 2 3 4 3 2 1 0
0 0 0 0 1 0 0 0 0 0 1 2 2 3 2 2 1 0
0 0 0 0 0 0 0 0 0 0 1 1 2 2 2 1 0 0
0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Hint: a single foldRight is sufficient. Which is the list you should apply it on?
*/
def effect(intensity: Int, img: Img): Img = ???