Edit this page Backlinks This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. ====== Homework 1. Sets as functions ====== ===== Problem statement ===== Sets are **unordered** collections of **unique** elements. There are several ways to store sets. One of them relies on **characteristic functions**. Such **functional sets** are especially useful if we expect many **insert/retrieve** operations and less **traversals** in our code. A **characteristic function** of a set $math[A \subseteq U] is a function $math[f: U \rightarrow \{0,1\}] which assigns $math[f(x) = 1] for each element $math[x \in A] and $math[f(x) = 0] for each element $math[x \not\in A]. In our implementation, $math[U] will be the set of integers, hence we shall encode only **sets of integers**. Hence, the type of a set will be: <code scala> type Set = Int => Boolean </code> For instance, the set $math[\{1,2,3\}] will be encoded by the anonymous function: <code scala> (x: Int) => (x == 1 || x == 2 || x == 3) </code> Also, the empty set can be encoded as: <code scala> (x: Int) => false </code> while the entire set of integers may be encoded as: <code scala> (x: Int) => true </code> **1.** Write a function ''singleton'' which takes an integer and returns **the set** containing only that integer: <code scala> def singleton(x: Int): Set = ??? </code> Note that ''singleton'' could have been equivalently defined as: ''def singleton(x: Int)(e: Int): Boolean = ???'', however, the previous variant is more legible, in the sense that it highlights the idea that we are returning **set objects**, namely **characteristic functions**. **2.** Write a function ''member'' which takes an integer $math[e] and a set $math[s] and checks if $math[e \in s]. Note that ''member'' should be defined and called as a curry function: <code scala> def member(e: Int)(s: Set): Boolean = ??? </code> **3.** Write a function ''ins'' which inserts a new element in a set. More precisely, given $math[x] and $math[s], ''ins'' returns the new set $math[\{x\} \cup s]. <code scala> def ins(x: Int)(s: Set): Set = ??? </code> **4.** Write a function ''fromBounds'' which takes two integer bounds ''start'' and ''stop'' and returns the set $math[\{start, start+1, \ldots, stop\}]. It is guaranteed that $math[start \leq stop] (you do not need to check this condition in your implementation). <code scala> def fromBounds(start: Int, stop: Int): Set = ??? </code> **5.** Write the function which performs the union of two sets: <code scala> def union(set1: Set, set2: Set): Set = ??? </code> **6.** Write a function which computes the complement of a set with respect to the set of integers: <code scala> def complement(s1: Set): Set = ??? </code> **7.** Write a function which computes the sum $math[b + e_0 + e_1 + ... e_n] where each $math[e_i] is in the interval $ [start,stop]$ and also in $math[s]. Use a tail-end recursive function: <code scala> def sumSet(b: Int)(start: Int, stop: Int)(s: Set): Int = { def auxSum(crt: Int, acc: Int): Int = ??? ??? } </code> **8.** Generalise the previous function such that we can **fold** a set using any binary commutative operation over integers. Make sure this is a **left** fold: Folding the set: ''{x,y,z}'' with initial value ''b'' should produce: ''( (b op x) op y) op z'' <code scala> def foldLeftSet (b:Int) // initial value (op: (Int,Int) => Int) // folding operation (start: Int, stop: Int) // bounds (inclusive) (set: Set): Int = ??? // the set to be folded </code> **9.** Implement an alternative to the previous function, namely **foldRight**. Applying ''foldRight'' on the set ''{x,y,z}'' with initial value ''b'' should produce: ''a op (b op (c op b))''. Use direct recursion instead of tail recursion. <code scala> def foldRightSet (b:Int) // initial value (op: (Int,Int) => Int) // folding operation (start: Int, stop: Int) // bounds (inclusive) (set: Set): Int = ??? // the set to be folded </code> **10.** Implement operation ''filter'' which takes a set and returns the set containing only those elements $math[e] for which $math[p(e)] is true: <code scala> def filter(p: Int => Boolean)(s: Set): Set = ??? </code> **11.** Implement a function which **partitions** a set into two sets. The left-most contains those elements that satisfy the predicate $math[p], while the right-most contains those elements that do not satisfy the predicate. Use pairs. A pair is constructed with simple parentheses. E.g. ''(1,2)'' is a pair of two integers. Suppose ''val p: (Int,Int)'' is a pair of two integers. Then ''p._1'' is the left-most part of the pair while ''p._2'' is the right-most part of the pair. <code scala> def partition(p: Int => Boolean)(s: Set): (Set,Set) = ??? </code> **12.** Implement a function ''forall'' which checks if all elements in a given range from a set satisfy the predicate $math[p]. (For instance $math[p] might be used to describe even numbers). <code scala> def forall(cond: Int => Boolean) // condition to be checked (start: Int, stop: Int) // start,stop values (inclusive) (s: Set): Boolean // set to be checked = ??? </code> **13.** Implement a function ''exists'' which checks if a predicate holds for **some** element from the range of a set. Hint: it is easier to implement ''exists'' using the logical relation: $math[ \exists x. P(X) \iff \lnot \forall x.\lnot P(X)]. <code scala> def exists(cond: Int => Boolean) // condition to be checked (start: Int, stop: Int) // start,stop values (inclusive) (s: Set): Boolean // set to be checked = ??? </code> **14.** Implement the function ''setOfDivByK'' which returns the set of integers divisible by a value ''k''. Use the appropriate functions you have defined previously in the homework. <code scala> def setOfDivByK(k: Int): Set = ??? </code> **15.** Implement the function ''moreDivs'' which verifies if ''set1'' contains more divisors of ''k'' than ''set2'', over the range $ [start,stop]$. Use any combination of the previous functions you have defined for your implementation. <code scala> def moreDivs(k: Int)(start: Int, stop:Int)(set1: Set, set2: Set): Boolean = ??? </code> ===== Submission rules ===== * Please follow the [[fp2025:submission-guidelines| Submission guidelines]] which are the same for all homework. * To solve your homework, download the {{:fp2025:hw1-functions-as-sets.zip| Project template}}, import it in IntellIJ, and you are all set. Do not rename the project manually, as this may cause problems with IntellIJ.