Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision | |||
pp:l04 [2023/03/16 13:46] alexia.ciuclea |
pp:l04 [2023/03/22 18:54] (current) mihai.udubasa old revision restored (2021/03/28 20:51) |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== 3. Lists in Scala ====== | + | ====== 4. Working with matrices and images using higher-order functions ====== |
- | Objectives: | + | ===== 1. Introduction ===== |
- | * get familiar with **pattern matching** lists, as well as common list operations from Scala and how they work | + | |
- | * get familiar with common **higher-order functions** over lists (partition, map, foldRight, foldLeft, filter) | + | |
- | ===== 3.1 Common list operations ===== | + | We shall represent matrices as //lists of lists//, i.e. values of type ''[ [Integer ] ]''. Each element in the outer list represents a line of the matrix. |
+ | Hence, the matrix | ||
- | **3.1.1.** Write a function which returns true if a list of integers has at least k elements. Use patterns. | + | $math[ \displaystyle \left(\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right)] |
- | Write a second function that returns true if a list of integers has at least k elements that satisfy a predicate. | + | |
- | <code scala> | + | will be represented by the list ''[ [1,2,3],[4,5,6],[7,8,9] ]''. |
- | def atLeastk(k: Int, l: List[Int]): Boolean = | + | |
- | if (k == 0) ??? | + | To make signatures more legible, add the //type alias// to your code: |
- | else ??? | + | <code haskell> type Matrix = [[Integer]] </code> |
- | } | + | which makes the type-name ''Matrix'' stand for ''[ [Integer] ]''. |
- | + | ||
- | def atLeastkPred(pred: Int => Boolean)(k: Int, l: List[Int]): Boolean = ??? | + | 1.1. Write a function ''parsem'' which takes a string and parses it to a ''Matrix''. In the string, the columns are separated by whitespace and lines - by '\n'. |
+ | * (Hint: You need to perform two types of very similar splitting operations: one into lines, and another into column values, for each line) | ||
+ | |||
+ | <code haskell> | ||
+ | parsem :: String -> Matrix | ||
+ | parsem = | ||
</code> | </code> | ||
- | **3.1.2.** Write a function which returns the first ''n'' elements from a given list. The function should not be implemented as tail-recursive. | + | 1.2. Write a function that converts a matrix to a string encoded as illustrated in the previous exercise. |
- | <code scala> | + | * (Hint: use folds) |
- | def take(n: Int, l: List[Int]): List[Int] = ??? | + | * (Hint: test the function ''show'' on several different values) |
- | //take(3,List(1,2,3,4,5)) = List(1,2,3) | + | * (Hint: first make a function to display one line) |
+ | |||
+ | <code haskell> | ||
+ | toString:: Matrix -> String | ||
+ | toString= | ||
</code> | </code> | ||
- | **3.1.3.** Write a function which //drops// the first ''n'' elements from a given list. The function should not be implemented as tail-recursive. | + | 1.3. Add the following to your code. Test the function ''displayMatrix''. |
- | <code scala> | + | <code haskell> |
- | def drop(n: Int, l: List[Int]): List[Int] = ??? | + | displayMatrix = putStrLn . toString |
- | //drop(3,List(1,2,3,4,5)) = List(4,5) | + | |
</code> | </code> | ||
- | **3.1.4.** Write a function which takes a predicate ''p: Int => Boolean'', a list ''l'' and returns a sublist of ''l'' containing those elements for which ''p'' is true. The function should be **curried**. | + | ===== 2. Matrix operations ===== |
- | <code scala> | + | |
- | def takeP(p: Int => Boolean)(l: List[Int]): List[Int] = ??? | + | 2.1. Write a function that computes the scalar product with an integer: |
- | //takeP(_%2 == 0)(List(1,2,3,4,5,6)) = List(2,4,6) | + | |
+ | $math[ \displaystyle 2 * \left(\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right) = \left(\begin{array}{ccc} 2 & 4 & 6 \\ 8 & 10 & 12 \\ 14 & 16 & 18 \\ \end{array}\right)] | ||
+ | |||
+ | <code haskell> | ||
+ | vprod :: Integer -> Matrix -> Matrix | ||
+ | vprod v = | ||
</code> | </code> | ||
- | **3.1.5.** Write a function which uses a predicate to partition (split) a list. | + | 2.2. Write a function which adjoins two matrices by extending rows: |
- | <code scala> | + | |
- | def part(p: Int => Boolean)(l: List[Int]): (List[Int], List[Int]) = ??? | + | $math[ \displaystyle \left(\begin{array}{cc} 1 & 2 \\ 3 & 4\\\end{array}\right) hjoin \left(\begin{array}{cc} 5 & 6 \\ 7 & 8\\\end{array}\right) = \left(\begin{array}{cc} 1 & 2 & 5 & 6 \\ 3 & 4 & 7 & 8\\\end{array}\right) ] |
- | // part(_%2 == 0)(List(1,2,3,4,5,6)) = (List(2,4,6),List(1,3,5)) | + | |
+ | <code haskell> | ||
+ | hjoin :: Matrix -> Matrix -> Matrix | ||
+ | hjoin = | ||
</code> | </code> | ||
- | **3.1.6** Write a function that returns the max value from a list. '' Use foldRight''. | + | 2.3. Write a function which adjoins two matrices by adding new rows: |
- | <code scala> | + | |
- | def maxList(l: List[Int]): Int = ??? | + | $math[ \displaystyle \left(\begin{array}{cc} 1 & 2 \\ 3 & 4\\\end{array}\right) vjoin \left(\begin{array}{cc} 5 & 6 \\ 7 & 8\\\end{array}\right) = \left(\begin{array}{cc} 1 & 2 \\ 3 & 4 \\ 5 & 6\\ 7 & 8\\ \end{array}\right) ] |
+ | |||
+ | <code haskell> | ||
+ | vjoin :: Matrix -> Matrix -> Matrix | ||
+ | vjoin = | ||
</code> | </code> | ||
- | **3.1.7** Reverse a list using folds. | + | 2.4. Write a function which adds two matrices. |
- | <code scala> | + | |
- | def reverseList(l: List[Int]): List[Int] = ??? | + | <code haskell> |
+ | msum :: Matrix -> Matrix -> Matrix | ||
+ | msum = | ||
</code> | </code> | ||
- | ==== 3.2 Gradebooks ==== | + | 2.5. Write a function which computes the transposition of a matrix: |
- | More general implementation of ''take'', ''drop'' and ''part'' are already implemented in Scala and can be used as member functions of lists. Examples are shown below: | + | |
- | <code scala> | + | $math[ tr \left(\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \\ \end{array}\right) = \left(\begin{array}{ccc} 1 & 4 & 7 \\ 2 & 5 & 8 \\ 3 & 6 & 9 \\ \end{array}\right) ] |
- | val l = List(1,2,3,4,5,6,7,8,9) | + | |
- | l.take(3) | + | <code haskell> |
- | l.drop(3) | + | tr :: [[a]] -> [[a]] |
- | l.partition(_%2 == 0) | + | tr ([]:_) = |
+ | tr m = | ||
</code> | </code> | ||
- | In what follows, we shall encode a gradebook as a list of pairs ''(<name>,<grade>)'', where ''<name>'' is a String and ''<grade>'' is an Int. Example: | + | 2.6. Write a function which computes the vectorial product of two matrices. |
- | <code scala> | + | * (Hint: start by writing a function which computes $math[a_{ij}] for a given line $math[i] and column $math[j] (both represented as lists)) |
- | val gradebook = List(("G",3), ("F", 10), ("M",6), ("P",4)) | + | * (Hint: write a function which takes a line of matrix m1 and the matrix m2 and computes the respective line from the product) |
- | </code> | + | |
- | To make the type signatures more legible, we can introduce type aliases in Scala: | + | <code haskell> |
- | <code scala> | + | mprod :: Matrix -> Matrix -> Matrix |
- | type Gradebook = List[(String,Int)] //the type Gradebook now refers to a list of pairs of String and Int | + | mprod m1 m2 = |
</code> | </code> | ||
- | Add this type alias to your code before solving the following exercises. | ||
- | **3.2.1.** Write a function which adds one point to all students which have a passing grade (>= 5), and leaves all other grades unchanged. | + | ===== 3. Image operations ===== |
- | <code scala> | + | |
- | def increment(g: Gradebook): Gradebook = | + | We can represent images as matrices of pixels. In our example a pixel will be represented as a ''Char'', which can take the values: '*' (signifying that the respective pixel is //on//) and ' ' (the pixel is off). |
- | g.map(???) | + | |
+ | <code haskell> type Image = [String] </code> | ||
+ | |||
+ | For instance, a rectangle could be represented as: | ||
+ | |||
+ | <code> | ||
+ | ******** | ||
+ | * * | ||
+ | ******** | ||
</code> | </code> | ||
- | **3.2.2.** Find the average grade from a gradebook. You must use ''foldRight''. | + | more precisely, as the string: |
- | <code scala> | + | <code haskell> |
- | def average(g: Gradebook): Double = ??? | + | "********\n* *\n********\n" |
</code> | </code> | ||
- | **3.2.3.** Write a function which takes a gradebook and returns the percentage of failed vs. passed students, as a pair (x,y). | + | 3.1. Implement an image-displaying function. Use the image from the Appendix as a test. |
- | <code scala> | + | <code haskell> |
- | def percentage(g: Gradebook): (Double,Double) = ??? | + | toStringImg :: Image -> String |
+ | toStringImg = | ||
</code> | </code> | ||
- | **3.2.4.** Write a function which takes a gradebook and returns the list of names which have passed. Use filter and map from Scala. | + | Add the following function in order to view images in a nicer format: |
- | <code scala> | + | <code haskell> |
- | def pass(g: Gradebook): List[String] = ??? | + | displayImg = putStrLn . toStringImg |
</code> | </code> | ||
- | **3.2.5.(!)** Implement merge-sort (in ascending order) over gradebooks: | + | 3.2. Implement a function which flips an image horizontally: |
- | <code scala> | + | <code haskell> |
- | def mergeSort(l: Gradebook): Gradebook = { | + | flipH :: Image -> Image |
- | def merge(u: Gradebook, v: Gradebook): Gradebook = ??? | + | flipH = |
- | ??? | + | |
- | } | + | |
</code> | </code> | ||
- | **3.2.6.(!)** Write a function which takes a gradebook and reports all passing students in **descending** order of their grade. | + | 3.3. Implement a function which flips an image vertically: |
- | <code scala> | + | <code haskell> |
- | def honorsList(g: Gradebook): List[String] = ??? | + | flipV :: Image -> Image |
+ | flipV = | ||
</code> | </code> | ||
+ | |||
+ | 3.4. Implement a function which rotates an image 90grd clockwise | ||
+ | <code haskell> | ||
+ | rotate90r :: Image -> Image | ||
+ | rotate90r = | ||
+ | </code> | ||
+ | |||
+ | 3.5. Implement a function which rotates an image -90grd clockwise | ||
+ | <code haskell> | ||
+ | rotate90l :: Image -> Image | ||
+ | rotate90l = | ||
+ | </code> | ||
+ | |||
+ | 3.6. Implement a function which inverts an image: ' ' becomes * and * becomes ' ': | ||
+ | <code haskell> | ||
+ | invert :: Image -> Image | ||
+ | invert = | ||
+ | </code> | ||
+ | |||
+ | 3.7. Implement a function ''maskKeep'' which takes a mask and some image and only keeps the part of image which overlays the mask. Use the mask and the logo from Appendix to test it. | ||
+ | <code haskell> | ||
+ | maskKeep :: Image -> Image -> Image | ||
+ | maskKeep = | ||
+ | </code> | ||
+ | $math[ maskKeep \left(\begin{array}{ccc} & & * \\ & & * \\ & & * \\ \end{array}\right) \left(\begin{array}{ccc} * & & * \\ * & & \\ * & & * \\ \end{array}\right) = \left(\begin{array}{ccc} & & * \\ & & \\ & & * \\ \end{array}\right) ] | ||
+ | |||
+ | 3.8. Implement a function ''maskDiscard'' which takes a mask and some image and discards the part of the mask which overlays the image. | ||
+ | |||
+ | $math[ maskDiscard\left(\begin{array}{ccc} & & * \\ & & * \\ & & * \\ \end{array}\right) \left(\begin{array}{ccc} * & & * \\ * & & \\ * & & * \\ \end{array}\right) = \left(\begin{array}{ccc} & & \\ & & * \\ & & \\ \end{array}\right) ] | ||
+ | |||
+ | 3.9. Implement the ''union''' of two images. | ||
+ | <code haskell> | ||
+ | union' :: Image -> Image -> Image | ||
+ | union' = | ||
+ | </code> | ||
+ | $math[ union \left(\begin{array}{ccc} & & * \\ & & * \\ & & * \\ \end{array}\right) \left(\begin{array}{ccc} * & & * \\ * & & \\ * & & * \\ \end{array}\right) = \left(\begin{array}{ccc} * & & * \\ * & & * \\ * & & * \\ \end{array}\right) ] | ||
+ | |||
+ | 3.10. Implement a function which takes a list of transformation and an image and applies all those transformations. | ||
+ | <code haskell> | ||
+ | transformationSequence :: [Image -> Image] -> Image -> Image | ||
+ | </code> | ||
+ | Test it with the following sequence | ||
+ | <code haskell> | ||
+ | seq1 = transformationSequence [invert, union' mask, rotate90r] | ||
+ | </code> | ||
+ | |||
+ | ===== 4. More matrices ===== | ||
+ | |||
+ | 4.1. Implement a function which places zeros **above** the diagonal of a square matrix. Use folds. | ||
+ | |||
+ | 4.2. Implement a function which places zeros **below** the diagonal of a square matrix. Use folds. | ||
+ | |||
+ | 4.3. Implement either of 4.1 or 4.2 using the function(s) ''take'' and ''drop''. Check the types of these and test them. | ||
+ | |||
+ | 4.4. Implement a function which computes the **diagonal** matrix of a square matrix. | ||
+ | |||
+ | 4.5. Implement a function which computes **recursively** the determinant of a matrix. What additional functions would be necessary? | ||
+ | |||
+ | ===== Appendix ===== | ||
+ | |||
+ | <code haskell> | ||
+ | logo = [l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19] | ||
+ | where l1 =" ***** ** ***** ** " | ||
+ | l2 =" ****** **** ****** **** " | ||
+ | l3 =" ** * * *** ** * * *** " | ||
+ | l4 =" * * * *** * * * *** " | ||
+ | l5 =" * * ** * * ** " | ||
+ | l6 =" ** ** ** ** ** ** " | ||
+ | l7 =" ** ** ** ** ** ** " | ||
+ | l8 =" **** ** * **** ** * " | ||
+ | l9 =" * *** ** * * *** ** * " | ||
+ | l10=" ** ******* ** ******* " | ||
+ | l11=" ** ****** ** ****** " | ||
+ | l12=" ** ** ** ** " | ||
+ | l13=" ** ** ** ** " | ||
+ | l14=" ** ** ** ** " | ||
+ | l15=" ** ** ** ** ** ** " | ||
+ | l16="*** * * *** * * " | ||
+ | l17=" *** * *** * " | ||
+ | l18=" ****** ****** " | ||
+ | l19=" *** *** " | ||
+ | </code> | ||
+ | |||
+ | <code haskell> | ||
+ | mask = [l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19] | ||
+ | where l1 =" *****************" | ||
+ | l2 =" *****************" | ||
+ | l3 =" *****************" | ||
+ | l4 =" *****************" | ||
+ | l5 =" *****************" | ||
+ | l6 =" *****************" | ||
+ | l7 =" *****************" | ||
+ | l8 =" *****************" | ||
+ | l9 =" *****************" | ||
+ | l10=" *****************" | ||
+ | l11=" *****************" | ||
+ | l12=" *****************" | ||
+ | l13=" *****************" | ||
+ | l14=" *****************" | ||
+ | l15=" *****************" | ||
+ | l16=" *****************" | ||
+ | l17=" *****************" | ||
+ | l18=" *****************" | ||
+ | l19=" *****************" | ||
+ | </code> | ||
+ | |||
+ | |||