Last updated on
Week 11 Debrief: Midterms solutions are available!
Congrats on completing your 11th week of CS-214! Here is a round-up of interesting questions, tips for exercises and labs, and general notes about the course.
Administrivia
- The midterm grade and solutions are online!
Interesting Ed questions
-
Unguided webapp
-
Laziness
-
Scala
-
Exercises - safe effects
Unguided lab updates
Our advice for this week
At this point, you should have a minimum viable prototype: a version of your app that does just a fraction of what it needs to do, but which captures the essence of your idea. This week, we recommend that you build a second prototype, now with almost all functionality complete:
- Backend: All state transitions and projections;
- Frontend: Complete UI and actions triggering transitions;
- Tests: Complete unit and integration tests, based on last week’s diagrams.
The idea is to keep a full week for debugging, polishing things up, preparing your demo, etc.
Common mistakes from the midterm
Proof
Question 5
- Missing parentheses after applying the induction hypothesis (IH). Writing:
f(x) :: (xs ++ lst2).map(f) f(x) :: xs.map(f) ++ lst2.map(f) // by IHThe correct version is:
f(x) :: (xs ++ lst2).map(f) f(x) :: (xs.map(f) ++ lst2.map(f)) // by IH f(x) :: xs.map(f) ++ lst2.map(f) // by ConsAppendOmitting the parentheses skips an essential proof step.
- Applying IH to
x :: xsinstead of toxs.((x :: xs) ++ lst2).map(f) (x :: xs).map(f) ++ lst2.map(f) // by IHStructural induction on lists corresponds to induction on their length. The IH holds for lists of length
n = xs.length, and we must prove the result for lengthn + 1(i.e.,x :: xs). Thus, IH applies toxs, not tox :: xs.
Variance
Question 15
-
Instantiating a trait directly.
trait T[A]: def i: Int val a = T[Int]() // Not Found Error: Not found: TSince traits may contain abstract methods, Scala requires you to either:
- Define a subclass:
class C extends T[Int]: def i: Int = 1 val a = C[Int]() - Use an anonymous class:
val a = new T[Int]: def i: Int = 1
- Define a subclass:
-
Upcasting. Given
trait I[+T], the following fails:val cAny: I[Any] = <some_code> val cInt: I[Int] = cAny // Type Mismatch Error: Found: I[Any] Required: I[Int]Covariance means that
I[Int] <: I[Any], not the other way around. -
Not specializing the class. The following code, would still work at runtime:
class C[T] extends I[T]: def t: T = ??? def f(a: T): T = a val cInt: I[Int] = C() val cAny: I[Any] = cInt val result = cAny.f("Hello") // Works!Due to ensure, type parameters are conceptually substituted by
Any(more precisely by JavaObjects). SocAny.f("Hello")works at runtime and simply returns"Hello".
Parallelism and complexity
Question 16
- Using
isSpecialas a method on String (word.isSpecial), instead ofisSpecial(word).class A: def methodOnA = "true" def methodTakingA(a: A) = "true" val functionTakingA = (a: A) => "true" // like `isSpecial` extension (a: A) def extensionMethodOnA = "true" //usage val a = A() a.methodOnA methodTakingA(a) functionTakingA(a) a.extensionMethodOnA - Using conditions from the example tests rather than the provided predicate. The task specified counting words based on the predicate
isSpecial.
Question 17
- Returning the wrong type
Seq[Map[String, Int]]instead ofFrequencies. Example problematic code:freqs1.map((k, v) => freqs2.updated(k, v + freqs2.getOrElse(k, 0)))But aggregate has signature:
def aggregate[B](z: => B)(seqop: (B, A) => B, combop: (B, B) => B): BSo in the following usage
<some_code>.aggregate(<some_code>)(<some_code>, comb)combneeds to conform to(B, B) => B, and looking atcombparameters it must be thatB = Frequencies, socombmust returnFrequencies. - Losing values from the first map by using
++.(freqs1 ++ freqs2).<some_code>Remember that if both maps have a value another the same key, only the first one is lost.
Map(1 -> "yay", 2 -> "forget me not") ++ Map(2 -> "yay") // Map(1 -> "yay", 2 -> "yay") - Dropping keys that appear only in one map.
freqs1.map((k, b) => (k, v + freqs2.getOrElse(k, 0)))The result has only the keys that appear in
freqs1.Map(1 -> 0).map((k, b) => (k, v + Map(2 -> 3).getOrElse(k, 0))) // Map(1 -> 0)
Question 18
- Leaving the result as some formula, e.g.:
- max of …,
- recursive complexity definition:
W(n) = something * W(n-1) …, - in terms of the work/depth of other functions:
W(n) = W_cohesion + W_avoidance.
Campus renovation
Question 21
- Forgetting to check if the building is in boundaries by calling
inBoundaries. - Not using intersect, resulting in deeply nested
foralls:c.buildings.forall(_.coords.forall(c => b.coords.forall(c != _)))Succinctness was one of the grading criteria!
Question 25
- Returning a
Set[Set[CampusPlan]]instead of justSet[CampusPlan](missing flatten). - Not using the helper functions provided in the assignment. Again, succinctness was graded.
Question 26
- Not utilizing the most appropriate
stdlibfunctions, e.g. usingfoldLeftinstead ofsum, or usingreduceinstead ofmaxBy, which, again, influenced the succinctness of the solution. Having a solid grasp of the availablestdlibutilities can save you time, prevent unnecessary reimplementation, and make your code more concise and readable.