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.

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 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:

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 = ???