diff --git a/README.md b/README.md index 961755b42853bec9a4d90ae3718719916e3b9fa5..74f91622357a3622fac0296bd14766c39a81d492 100644 --- a/README.md +++ b/README.md @@ -1,269 +1,3 @@ -This repository will be used as the website for Functional Programming CS-210. It will be updated weekly throughout the semester. This README contains general information about the class. +# CS-210 Functional Programming -- [previous-exams](previous-exams) contains PDFs for the previous exams. -- [exercises](exercises) contains markdown documents for the exercise sessions and solutions. -- [slides](slides) contains the slides presented in class (also attached or respective videos). -- [labs](labs) contains markdown documents for the labs. - -We will use GitLab's issue tracker as a discussion forum. Feel free to [open an issue](https://gitlab.epfl.ch/lamp/cs210/issues/new) if you have any comments or questions - -# First-week Tasks - -1. [Join the Discord](https://discord.gg/UqzqX2wTWW). -2. [Log into EPFL's GitLab](https://gitlab.epfl.ch/users/sign_in). -3. Fill in [this table](https://docs.google.com/spreadsheets/d/12KvfD_jN5AcApmWhCz7xZmln48fctQOa984RPWrqRkY/edit#gid=0) with your GASPAR and SCIPER number to initialize your GitLab repository for the course (login with your `@epfl.ch` address to have write access). -4. Choose a group for the exercises (recitation sessions) by answering [this Doodle](https://doodle.com/poll/4k7gkxiv9hdxzivk). -5. Follow the [Tools Setup](labs/tools-setup.md) page. -6. Do the [example lab](labs/example-lab.md). -7. Do the [first graded lab](labs/lab-1.md). - -## Grading - -The grading of the course is divided between labs (30%), a midterm exam (20%) and a final exam (50%). - -## Staff - -| Role | People | -| :--- | :--- | -| Professors | [Martin Odersky](https://people.epfl.ch/martin.odersky), [Viktor Kunčak](https://people.epfl.ch/viktor.kuncak) | -| TAs | [Dragana Milovancevic](https://people.epfl.ch/dragana.milovancevic), [Ergys Dona](https://people.epfl.ch/ergys.dona), [Jean-Baptiste Cordonnier](https://people.epfl.ch/jean-baptiste.cordonnier), [Matthieu Bovel](https://people.epfl.ch/matthieu.bovel) | -| Student TAs | [Joshua Bernimoulin](https://people.epfl.ch/joshua.bernimoulin), [Mohamed Yassine Boukhari](https://people.epfl.ch/mohamed.boukhari), [Hind El Bouchrifi ](https://people.epfl.ch/hind.elbouchrifi), [Luca Giordano](https://people.epfl.ch/lucas.giordano), [Mohamed Hichem Hadhri](https://people.epfl.ch/mohamed.hadhri), [Salim Najib](https://people.epfl.ch/salim.najib), [Arthur Vignon](https://people.epfl.ch/arthur.vignon) | - -## Lecture Schedule - -<!-- date -d "30/09/2019 364 days" +"%d.%m.%Y" --> - -Lectures are prerecorded and published below. This class is given in a [_flipped classrom_](https://en.wikipedia.org/wiki/Flipped_classroom) format, meaning that you should watch the videos by yourself _before_ the indicated date. You will then have the occasion to test and perfect your knowledge during the [exercises (recitation sessions)](#user-content-exercise-recitation-session-schedule) on Wednesday afternoons, and [labs](#user-content-lab-schedule) on Friday mornings. - -**Note**: In some lectures, worksheets are used to present code. To learn how to -use worksheets yourselves, please follow the [Tools -Setup](labs/tools-setup.md) and [example lab](labs/example-lab.md). To create a -new empty project to experiment with worksheets, you can clone the following -repository and run `code . ` inside as usual: [`git clone https://gitlab.epfl.ch/lamp/cs210-worksheets`](https://gitlab.epfl.ch/lamp/cs210-worksheets) - -| Week | Date | Topic | Videos & Slides | -| :-- | :-- | :-- | :-- | -| 1 | 22.09.2021 | Intro class | Introduction ([Video][Video 1.1.1], [Slides][Slides 1.1.1])<br/>Elements of programming ([Video][Video 1.1.2], [Slides][Slides 1.1.2])<br/>Evaluation strategies and termination ([Video][Video 1.1.3], [Slides][Slides 1.1.3])<br/>Value Definitions and Conditionals ([Video][Video 1.1.4], [Slides][Slides 1.1.4])<br/>Square Roots with Newtons Methods ([Video][Video 1.1.5], [Slides][Slides 1.1.5])<br/>Blocks and lexical scopes ([Video][Video 1.1.6], [Slides][Slides 1.1.6])<br/>Tail Recursion ([Video][Video 1.1.7], [Slides][Slides 1.1.7]) | -| 2 | 29.09.2021 | Recursion / Function values | Higher-Order Functions ([Video][Video 1.2.1], [Slides][Slides 1.2.1])<br/>Currying ([Video][Video 1.2.2], [Slides][Slides 1.2.2])<br/>Finding FixedPoints ([Video][Video 1.2.3], [Slides][Slides 1.2.3])<br/>Scala Syntax Summary ([Video][Video 1.2.4], [Slides][Slides 1.2.4])<br/>Functions and Data ([Video][Video 1.2.5], [Slides][Slides 1.2.5])<br/>Data Abstraction ([Video][Video 1.2.6], [Slides][Slides 1.2.6])<br/>Evaluation and Operators ([Video][Video 1.2.7], [Slides][Slides 1.2.7]) | -| 3 | 06.10.2021 | Classes | Class Hierarchies ([Video][Video 1.3.1], [Slides][Slides 1.3.1])<br/>How Classes are Organized ([Video][Video 1.3.2], [Slides][Slides 1.3.2])<br/>Polymorphism ([Video][Video 1.3.3], [Slides][Slides 1.3.3])<br/>Objects Everywhere ([Video][Video 1.3.4], [Slides][Slides 1.3.4])<br/>Functions as Objects ([Video][Video 1.3.5], [Slides][Slides 1.3.5]) | -| 4 | 13.10.2021 | Classes | Decomposition ([Video][Video 1.4.1], [Slides][Slides 1.4.1])<br/>Pattern Matching ([Video][Video 1.4.2], [Slides][Slides 1.4.2])<br/>Lists ([Video][Video 1.4.3], [Slides][Slides 1.4.3])<br/>Enums ([Video][Video 1.4.4], [Slides][Slides 1.4.4])<br/>Subtyping and Generics ([Video][Video 1.4.5], [Slides][Slides 1.4.5])<br/>Variance ([Video][Video 1.4.6], [Slides][Slides 1.4.6]) | -| 5 | 20.10.2021 | List | A closer look at lists ([Video][Video 1.5.1], [Slides][Slides 1.5.1])<br/>Tuples and generic methods ([Video][Video 1.5.2], [Slides][Slides 1.5.2])<br/>Higher order list functions ([Video][Video 1.5.3], [Slides][Slides 1.5.3])<br/>Reduction of lists ([Video][Video 1.5.4], [Slides][Slides 1.5.4])<br/>Reasoning about lists ([Video][Video 1.5.5], [Slides][Slides 1.5.5]) | -| 6 | 27.10.2021 | Collection | Other Collections ([Video][Video 1.6.1], [Slides][Slides 1.6.1])<br/>Combinatorial Search and For-Expressions ([Video][Video 1.6.2], [Slides][Slides 1.6.2])<br/>Combinatorial Search Example ([Video][Video 1.6.3], [Slides][Slides 1.6.3])<br/>Maps ([Video][Video 1.6.4], [Slides][Slides 1.6.4])<br/>Putting the Pieces Together ([Video][Video 1.6.5], [Slides][Slides 1.6.5]) | -| 7 | 03.11.2021 | Monads | Recap ([Video][Video 2.1.1], [Slides][Slides 2.1.1])<br/>Queries with for ([Video][Video 2.1.2], [Slides][Slides 2.1.2])<br/>Translation of for ([Video][Video 2.1.3], [Slides][Slides 2.1.3])<br/>Functional Random Generators ([Video][Video 2.1.4], [Slides][Slides 2.1.4])<br/>Monads ([Video][Video 2.1.5], [Slides][Slides 2.1.5])<br/>Exceptional Monads ([Video][Video 2.1.6], [Slides][Slides 2.1.6]) | -| 8 | 10.11.2021 | **Midterm exam** | - | -| 9 | 17.11.2021 | Lazy evaluation | Structural Induction on Trees ([Video][Video 2.2.1], [Slides][Slides 2.2.1])<br/>Lazy Lists ([Video][Video 2.2.2], [Slides][Slides 2.2.2])<br/>Lazy Evaluation ([Video][Video 2.2.3], [Slides][Slides 2.2.3])<br/>Infinite Sequences ([Video][Video 2.2.4], [Slides][Slides 2.2.4])<br/>Case Study ([Video][Video 2.2.5], [Slides][Slides 2.2.5]) | -| 10 | 24.11.2021 | Type-directed computation | Contextual abstraction ([Video][Video 2.3.1], [Slides][Slides 2.3.1])<br/>Using clauses and given instances ([Video][Video 2.3.2], [Slides][Slides 2.3.2])<br/>Type classes ([Video][Video 2.3.3], [Slides][Slides 2.3.3])<br/>Abstract algebra and type classes ([Video][Video 2.3.4], [Slides][Slides 2.3.4])<br/>Context passing ([Video][Video 2.3.5], [Slides][Slides 2.3.5])<br/>Implicit function types ([Video][Video 2.3.6], [Slides][Slides 2.3.6]) | -| 11 | 01.12.2021 | State | Functions and state ([Video][Video 2.4.1], [Slides][Slides 2.4.1])<br/>Identity and change ([Video][Video 2.4.2], [Slides][Slides 2.4.2])<br/>Loops ([Video][Video 2.4.3], [Slides][Slides 2.4.3])<br/>Discrete Event Simulation ([Video][Video 2.4.4], [Slides][Slides 2.4.4]) | -| 12 | 08.12.2021 | Interpreter I | Interpreter for Arithmetic ([Video][Video 3.1.1], [Slides][Slides 3.1.1])<br/>Substitution Interpreter for Recursive Functions ([Video][Video 3.1.2], [Slides][Slides 3.1.2])<br/>Environment Instead of Substitutions ([Video][Video 3.1.3], [Slides][Slides 3.1.3])<br/>Higher-Order Functions Using Naive Substitutions ([Video][Video 3.1.4], [Slides][Slides 3.1.4])<br/>Avoiding Variable Capture ([Video][Video 3.1.5], [Slides][Slides 3.1.5])<br/>Higher-Order Functions Using Environments ([Video][Video 3.1.6], [Slides][Slides 3.1.6])<br/>Nested Recursive Definitions ([Video][Video 3.1.7], [Slides][Slides 3.1.7]) | -| 13 | 15.12.2021 | Parsing with Combinators / Lambda Calculus | Parsing with Combinators ([Video][Video 3.2.1], [Slides][Slides 3.2.1])<br/>Recursion as Self-Application ([Video][Video 3.2.2], [Slides][Slides 3.2.2])<br/>Church Numerals and Conditionals ([Video][Video 3.2.3], [Slides][Slides 3.2.3]) | -| 14 | 22.12.2021 | **Final exam** | - | - -## Exercise (Recitation Session) Schedule - -Exercises (aka recitation sessions) take place on Wednesdays from 13:15 to 15:00 in CO1, CO015, CO016, CO017, DIA004 and DIA005. Please go to the room that you registered to on Doodle. If you have forgotten which room you chose, please ask a TA on Discord (we cannot publish the whole list for privacy reasons). - -| Title | Handout Released | Session (Wednesdays 13:15 to 15:00) | Solution Released | -| :-- | :-- | :-- | :-- | -| First week tasks | - | 22.09.2021 | - | -| Exercise Session 1 | 27.09.2021 | 29.09.2021 | 04.10.2021 | -| Exercise Session 2 | 04.10.2021 | 06.10.2021 | 11.10.2021 | -| Exercise Session 3 | 11.10.2021 | 13.10.2021 | 18.10.2021 | -| Exercise Session 4 | 18.10.2021 | 20.10.2021 | 25.10.2021 | -| Exercise Session 5 | 25.10.2021 | 27.10.2021 | 01.11.2021 | -| Exercise Session 6 | 01.11.2021 | 03.11.2021 | 08.11.2021 | -| **Midterm exam** | - | 10.11.2021 | - | -| Exercise Session 7 | 15.11.2021 | 17.11.2021 | 22.11.2021 | -| Exercise Session 8 | 22.11.2021 | 24.11.2021 | 29.11.2021 | -| Exercise Session 9 | 29.11.2021 | 01.12.2021 | 06.12.2021 | -| Exercise Session 10 | 06.12.2021 | 08.12.2021 | 13.12.2021 | -| Exercise Session 11 | 13.12.2021 | 15.12.2021 | 20.12.2021 | -| **Final exam** | - | 22.12.2021 | - | - -Exercises are pen and paper style questions that will prepare you for the final exam. -Exercises should be done in groups. - -## Lab Schedule - -Lab sessions take place on Fridays from 10:15 to 12:00 in CO021, ELA1, ELD120, DIA005 and DIA004. - -| Title | Start Date | Session (Fridays 10:15 to 12:00) | Due Date ([AoE](https://en.wikipedia.org/wiki/Anywhere_on_Earth)) | -| :-- | :-- | :-- | :-- | -| Recursion | 22.09.2021 | 24.09.2021 | 03.10.2021 | -| Functional Sets | 29.09.2021 | 01.10.2021 | 07.10.2021 | -| Object-Oriented Sets | 06.10.2021 | 08.10.2021 | 14.10.2021 | -| Huffman Coding | 13.10.2021 | 15.10.2021 & 22.10.2021 | 28.10.2021 | -| Anagrams | 27.10.2021 | 29.10.2021 | 11.11.2021 | -| Quickcheck | 03.11.2021 | 05.11.2021 | 18.11.2021 | -| Bloxorz | 10.11.2021 | 12.11.2021 & 19.11.2021 | 25.11.2021 | -| Codecs | 24.11.2021 | 26.11.2021 & 03.12.2021 | 09.12.2021 | -| Interpreter | 08.12.2021 | 10.12.2021 & 17.12.2021 | 23.12.2021 | - -Labs are individual assignments where you get to write Scala programs using the concepts learned during lectures. -Labs are submitted by pushing your code on GitLab, see details in the [grading and submission](labs/grading-and-submission.md) page. - -## Exam Schedule - -- The midterm will be exercise-like, pen and paper, in-person, will last 1 hour and 45 minutes, and will take place on the __10th of November 2021 between 13:15 and 15:00__. Please wait by the door from 13:00, and we will open as soon as the rooms are ready so that you have time to seat and prepare yourself before the exam starts. - - We might ask you about anything that you have seen in the first 6 weeks of this course, including the [recap](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/slides/progfun2-1-1.pdf) at the beginning of week 7. - - No other material than a pen is allowed. In particular, no notes and no electronic equipment of any kind (computers, phones, smart watches, etc.). - - We will tell you to which room you are assigned and give you more information by email a few days before the exam. - - Please don't forget to bring your Camipro. You will also need a COVID certificate or a temporary COVID pass to attend the exam. [You can get a free temporary COVID pass by getting a salivary test here at EPFL](https://www.epfl.ch/campus/security-safety/en/health/coronavirus-covid19/covid-19-testing-center-epfl/). - -- The final exam will be on 22.12.2021. - - -[Video 1.1.1]: https://tube.switch.ch/videos/7ed71e65 -[Video 1.1.2]: https://tube.switch.ch/videos/eefaaa33 -[Video 1.1.3]: https://tube.switch.ch/videos/7ec55c9c -[Video 1.1.4]: https://tube.switch.ch/videos/f8abe6bf -[Video 1.1.5]: https://tube.switch.ch/videos/1f8d3205 -[Video 1.1.6]: https://tube.switch.ch/videos/9274e0f4 -[Video 1.1.7]: https://tube.switch.ch/videos/1843caa3 -[Slides 1.1.1]: ./slides/progfun1-1-1.pdf -[Slides 1.1.2]: ./slides/progfun1-1-2.pdf -[Slides 1.1.3]: ./slides/progfun1-1-3.pdf -[Slides 1.1.4]: ./slides/progfun1-1-4.pdf -[Slides 1.1.5]: ./slides/progfun1-1-5.pdf -[Slides 1.1.6]: ./slides/progfun1-1-6.pdf -[Slides 1.1.7]: ./slides/progfun1-1-7.pdf - -[Video 1.2.1]: https://tube.switch.ch/videos/646cfe4f -[Video 1.2.2]: https://tube.switch.ch/videos/9e573d2f -[Video 1.2.3]: https://tube.switch.ch/videos/0e2be793 -[Video 1.2.4]: https://tube.switch.ch/videos/ddcbb43f -[Video 1.2.5]: https://tube.switch.ch/videos/dec623bc -[Video 1.2.6]: https://tube.switch.ch/videos/6e8643cf -[Video 1.2.7]: https://tube.switch.ch/videos/p6uOZxpZO0 -[Slides 1.2.1]: ./slides/progfun1-2-1.pdf -[Slides 1.2.2]: ./slides/progfun1-2-2.pdf -[Slides 1.2.3]: ./slides/progfun1-2-3.pdf -[Slides 1.2.4]: ./slides/progfun1-2-4.pdf -[Slides 1.2.5]: ./slides/progfun1-2-5.pdf -[Slides 1.2.6]: ./slides/progfun1-2-6.pdf -[Slides 1.2.7]: ./slides/progfun1-2-7.pdf - -[Video 1.3.1]: https://tube.switch.ch/videos/56c88e00 -[Video 1.3.2]: https://tube.switch.ch/videos/1c969056 -[Video 1.3.3]: https://tube.switch.ch/videos/PE4EZHTXL1 -[Video 1.3.4]: https://tube.switch.ch/videos/9081e1da -[Video 1.3.5]: https://tube.switch.ch/videos/e409b899 -[Slides 1.3.1]: ./slides/progfun1-3-1.pdf -[Slides 1.3.2]: ./slides/progfun1-3-2.pdf -[Slides 1.3.3]: ./slides/progfun1-3-3.pdf -[Slides 1.3.4]: ./slides/progfun1-3-4.pdf -[Slides 1.3.5]: ./slides/progfun1-3-5.pdf - -[Video 1.4.1]: https://tube.switch.ch/videos/f5879da4 -[Video 1.4.2]: https://tube.switch.ch/videos/e7df77e5 -[Video 1.4.3]: https://tube.switch.ch/videos/978832a8 -[Video 1.4.4]: https://tube.switch.ch/videos/xmEdj2V0Xh -[Video 1.4.5]: https://tube.switch.ch/videos/9a844297 -[Video 1.4.6]: https://tube.switch.ch/videos/35c4e417 -[Slides 1.4.1]: ./slides/progfun1-4-1.pdf -[Slides 1.4.2]: ./slides/progfun1-4-2.pdf -[Slides 1.4.3]: ./slides/progfun1-4-3.pdf -[Slides 1.4.4]: ./slides/progfun1-4-4.pdf -[Slides 1.4.5]: ./slides/progfun1-4-5.pdf -[Slides 1.4.6]: ./slides/progfun1-4-6.pdf - -[Video 1.5.1]: https://tube.switch.ch/videos/8e9cf6a5 -[Video 1.5.2]: https://tube.switch.ch/videos/40edd184 -[Video 1.5.3]: https://tube.switch.ch/videos/af626839 -[Video 1.5.4]: https://tube.switch.ch/videos/e0e380fe -[Video 1.5.5]: https://tube.switch.ch/videos/9ebad679 -[Slides 1.5.1]: ./slides/progfun1-5-1.pdf -[Slides 1.5.2]: ./slides/progfun1-5-2.pdf -[Slides 1.5.3]: ./slides/progfun1-5-3.pdf -[Slides 1.5.4]: ./slides/progfun1-5-4.pdf -[Slides 1.5.5]: ./slides/progfun1-5-5.pdf - -[Video 1.6.1]: https://tube.switch.ch/videos/58a6fe2a -[Video 1.6.2]: https://tube.switch.ch/videos/a09a7679 -[Video 1.6.3]: https://tube.switch.ch/videos/7f2fcf99 -[Video 1.6.4]: https://tube.switch.ch/videos/a4519732 -[Video 1.6.5]: https://tube.switch.ch/videos/30005570 -[Slides 1.6.1]: ./slides/progfun1-6-1.pdf -[Slides 1.6.2]: ./slides/progfun1-6-2.pdf -[Slides 1.6.3]: ./slides/progfun1-6-3.pdf -[Slides 1.6.4]: ./slides/progfun1-6-4.pdf -[Slides 1.6.5]: ./slides/progfun1-6-5.pdf -[Slides 1.6.6]: ./slides/progfun1-6-6.pdf - -[Video 2.1.1]: https://tube.switch.ch/videos/680a1d2a -[Video 2.1.2]: https://tube.switch.ch/videos/935b0da5 -[Video 2.1.3]: https://tube.switch.ch/videos/2ac4c232 -[Video 2.1.4]: https://tube.switch.ch/videos/f9c5677b -[Video 2.1.5]: https://tube.switch.ch/videos/DJmNHpUHba -[Video 2.1.6]: https://tube.switch.ch/videos/fdfb0609 -[Slides 2.1.1]: ./slides/progfun2-1-1.pdf -[Slides 2.1.2]: ./slides/progfun2-1-2.pdf -[Slides 2.1.3]: ./slides/progfun2-1-3.pdf -[Slides 2.1.4]: ./slides/progfun2-1-4.pdf -[Slides 2.1.5]: ./slides/progfun2-1-5.pdf -[Slides 2.1.6]: ./slides/progfun2-1-6.pdf - -[Video 2.2.1]: https://tube.switch.ch/videos/0accfa13 -[Video 2.2.2]: https://tube.switch.ch/videos/fbd7e361 -[Video 2.2.3]: https://tube.switch.ch/videos/8506774b -[Video 2.2.4]: https://tube.switch.ch/videos/7064a6b1 -[Video 2.2.5]: https://tube.switch.ch/videos/889a5305 -[Slides 2.2.1]: ./slides/progfun2-2-1.pdf -[Slides 2.2.2]: ./slides/progfun2-2-2.pdf -[Slides 2.2.3]: ./slides/progfun2-2-3.pdf -[Slides 2.2.4]: ./slides/progfun2-2-4.pdf -[Slides 2.2.5]: ./slides/progfun2-2-5.pdf - -[Video 2.3.1]: https://tube.switch.ch/videos/d5df9a21 -[Video 2.3.2]: https://tube.switch.ch/videos/xRHmz1nTpz -[Video 2.3.3]: https://tube.switch.ch/videos/XNgbIOT2Yb -[Video 2.3.4]: https://tube.switch.ch/videos/FnmJTs1Vqu -[Video 2.3.5]: https://tube.switch.ch/videos/pWXI0T9FtX -[Video 2.3.6]: https://tube.switch.ch/videos/NKZ0IVR9Yi -[Slides 2.3.1]: ./slides/progfun2-3-1.pdf -[Slides 2.3.2]: ./slides/progfun2-3-2.pdf -[Slides 2.3.3]: ./slides/progfun2-3-3.pdf -[Slides 2.3.4]: ./slides/progfun2-3-4.pdf -[Slides 2.3.5]: ./slides/progfun2-3-5.pdf -[Slides 2.3.6]: ./slides/progfun2-3-6.pdf - -[Video 2.4.1]: https://tube.switch.ch/videos/f32bc013 -[Video 2.4.2]: https://tube.switch.ch/videos/7bf009ce -[Video 2.4.3]: https://tube.switch.ch/videos/zEyrIXFFPV -[Video 2.4.4]: https://tube.switch.ch/videos/CvuKzoNjRg -[Slides 2.4.1]: ./slides/progfun2-4-1.pdf -[Slides 2.4.2]: ./slides/progfun2-4-2.pdf -[Slides 2.4.3]: ./slides/progfun2-4-3.pdf -[Slides 2.4.4]: ./slides/progfun2-4-4.pdf - -[Video 2.5.1]: https://tube.switch.ch/videos/5ca69d05 -[Video 2.5.2]: https://tube.switch.ch/videos/700fc8b5 -[Video 2.5.3]: https://tube.switch.ch/videos/d93a3d12 -[Slides 2.5.1]: ./slides/progfun2-5-1.pdf -[Slides 2.5.2]: ./slides/progfun2-5-2.pdf -[Slides 2.5.3]: ./slides/progfun2-5-3.pdf - -[Video 3.1.1]: https://tube.switch.ch/videos/b053ad9d -[Video 3.1.2]: https://tube.switch.ch/videos/59b7ae00 -[Video 3.1.3]: https://tube.switch.ch/videos/0ccb68d7 -[Video 3.1.4]: https://tube.switch.ch/videos/0de70fa1 -[Video 3.1.5]: https://tube.switch.ch/videos/94bc1565 -[Video 3.1.6]: https://tube.switch.ch/videos/6d332501 -[Video 3.1.7]: https://tube.switch.ch/videos/18ba7117 -[Slides 3.1.1]: ./slides/progfun3-1-1.pdf -[Slides 3.1.2]: ./slides/progfun3-1-2.pdf -[Slides 3.1.3]: ./slides/progfun3-1-3.pdf -[Slides 3.1.4]: ./slides/progfun3-1-4.pdf -[Slides 3.1.5]: ./slides/progfun3-1-5.pdf -[Slides 3.1.6]: ./slides/progfun3-1-6.pdf -[Slides 3.1.7]: ./slides/progfun3-1-7.pdf - -[Video 3.2.1]: https://tube.switch.ch/videos/d08dd17f -[Video 3.2.2]: https://tube.switch.ch/videos/17841152 -[Video 3.2.3]: https://tube.switch.ch/videos/f203e6a9 -[Slides 3.2.1]: ./slides/progfun3-2-1.pdf -[Slides 3.2.2]: ./slides/progfun3-2-2.pdf -[Slides 3.2.3]: ./slides/progfun3-2-3.pdf +The material for the course CS-210 Functional Programming has moved to [Moodle](https://moodle.epfl.ch/course/view.php?id=14257). diff --git a/exercises/exercise-01.md b/exercises/exercise-01.md deleted file mode 100644 index 4c199b760978ac952c2e63fa25458cb8c5a083ee..0000000000000000000000000000000000000000 --- a/exercises/exercise-01.md +++ /dev/null @@ -1,59 +0,0 @@ -# Exercise Session 1 - -We will work on tail recursion in this session. - -## Question 1: Factorial - -Recall the factorial function that you saw in class - -```scala -def factorial(n: Int): Int = if (n <= 0) 1 else n * factorial(n - 1) -``` - -Define a tail recursive version of it - -```scala -def factorial(n: Int): Int = fact(n, 1) -@tailrec -def fact(n: Int, acc: Int): Int = ??? -``` - -What would be the advantage of making `fact` an inner function to `factorial`? - -## Question 2: Sum of elements on a list - -Define a function that takes a list of integers and sums them. You can use the functions `head`, `tail`, and `isEmpty` on lists, as you have seen for your homework. - -```scala -def sumList(ls: List[Int]): Int = ??? -``` - -Convert your definition into a tail-recursive one. - -## Question 3: Fast exponentiation - -Fast exponentiation is a technique to optimize the exponentiation of numbers: - -``` -b²ⁿ = (b²)ⁿ = (bⁿ)² -b²ⁿ⁺¹ = b * b²ⁿ -``` - -Define a function that implements this fast exponentiation. Can you define a tail recursive version as well? - -```scala -def fastExp(base: Int, exp: Int): Int = ??? -``` - -## Question 4: Tail recursive Fibonacci - -Define a function that computes the nth Fibonacci number. Can you define a tail recursive version as well? The Fibonacci recurrence is given as follows: - -``` -fib(n) = n | n = 0, 1 -fib(n) = fib(n - 1) + fib(n - 2) | otherwise -``` - -```scala -def fibonacci(n: Int): Int = ??? -``` diff --git a/exercises/exercise-02.md b/exercises/exercise-02.md deleted file mode 100644 index c0ddb94e145e4f046446b35abfa62e38f8df9c5f..0000000000000000000000000000000000000000 --- a/exercises/exercise-02.md +++ /dev/null @@ -1,114 +0,0 @@ -# Exercise Session 2 - -This week we will work on playing with functions as values. - -## Question 1 - -Define the function `flip`. It takes a function and returns the same function, but with the arguments flipped. - -```scala -def flip(f: (Int, Double) => Int): (Double, Int) => Int = ??? -``` - -## Question 2 - -### Question 2.1 - -Define the identity function for integers, which, given an `Int`, returns it. - -```scala -val id: Int => Int = ??? -``` - -### Question 2.2 - -Define the compose function, that, given 2 functions `f`, `g`, returns a function that composes them, i.e., `f ∘ g`. - -```scala -def compose(f: Int => Int, g: Int => Int): Int => Int = ??? -``` - -What does `compose(id, f)(k)` evaluate to, for some function `f` and integer `k`? - -### Question 2.3 - -Define the function `repeated`, which takes a function and repeatedly applies it `n` times (`n ≥ 0`). - -```scala -def repeated(f: Int => Int, n: Int): Int => Int = ??? -``` - -_Hint_: What values should be returned by `repeated(x => x + 1, 0)` and `repeated(x => x + 1, 3)`? - -## Question 3 - -### Question 3.1 - -Define the function `curry2`, that curries a two arguments function. That is, `curry2(f) = g` such that `f(x, y) == (g(x))(y)` - -```scala -def curry2(f: (Double, Int) => Boolean): Double => (Int => Boolean) = ??? -``` - -_Hint_: what should `curry2((x, y) => x < y)(1.0)` return? - - -### Question 3.2 - -Define the function `uncurry2`. It takes a curried function, and creates a two-argument function. - -```scala -def uncurry2(f: Double => Int => Boolean): (Double, Int) => Boolean = ??? -``` - -## Question 4 - -Write a function `fixedPoint` with the following signature: - -```scala -def fixedPoint(f: Int => Int): Int => Int -``` - -The function takes a function `f` and returns a function that maps an integer into the fixed point of f that is obtained by iterating `f` some finite number of times starting from the initial value. - -A value `x` is a fixed point of `f` if `f(x) == x`. - -For each of the following expressions, indicate whether it terminates, and if so, what is the value returned: - -- `fixedPoint(x => x/2)(4)` -- `fixedPoint(id)(123456)` -- `fixedPoint(x => x + 1)(0)` -- `fixedPoint(x => if (x % 10 == 0) x else x + 1)(35)` -- `fixedPoint((x: Int) => x / 2 + 5)(20)` - -## Question 5 - -### Question 5.1 - -Write the `sum` function with the following signature: - -```scala -def sum(f: Int => Int)(a: Int, b: Int): Int = ??? -``` - -Which returns the sum of `f(i)` where `i` ranges from `a` to `b`. - -_Bonus point_: Can your implementation be tail recursive ? - -### Question 5.2 - -Write the `quadratic` function with the following signature: - -```scala -def quadratic(c: Int): Int => Int = ??? -``` - -Which returns a function that takes an integer `x` as argument and returns `(x - c)²`. - -### Question 5.3 - -Using the above functions, define the function `quad3Integrate` which, given two integers `a` and `b`, computes the sum of `(i - 3)²` where `i` ranges from `a` to `b`. - -```scala -val quad3Integrate: (Int, Int) => Int = ??? -``` diff --git a/exercises/exercise-03.md b/exercises/exercise-03.md deleted file mode 100644 index f09c99913b60402976abbd56b16a496d54657e4e..0000000000000000000000000000000000000000 --- a/exercises/exercise-03.md +++ /dev/null @@ -1,81 +0,0 @@ -# Exercise Session 3 - -This week we will play with genericity and object-oriented programming concepts. - -A [_binary search_](https://en.wikipedia.org/wiki/Binary_search_tree) tree is a binary tree such that, for a node, all elements in the left sub-tree are smaller than the element at the node, and all elements in the right sub-tree are greater than the element at the node. Therefore, binary search trees do not contain duplicate elements. - -Because we want to build a generic tree structure, we also need the notion of a comparator, or a less-than-or-equal operator (denoted `leq`) for two generic elements which satisfies the following properties: - -- Transitivity: `leq(a, b) && leq(b, c) => leq(a, c)`. -- Reflexivity: `leq(a, a)` is `true`. -- Anti-symmetry: `leq(a, b) && leq(b, a) => a == b`. -- Totality: either `leq(a, b)` or `leq(b, a)` is `true` (or both). - -Note that the above defines a [_total order_](https://en.wikipedia.org/wiki/Total_order). - -Here is the structure we will be using for implementing these trees: - -```scala -trait Tree[T] -case class EmptyTree[T](leq: (T, T) => Boolean) extends Tree[T] -case class Node[T](left: Tree[T], elem: T, right: Tree[T], leq: (T, T) => Boolean) extends Tree[T] -``` - -For consistency, all subtrees must contain the same leq parameter. -Creating an empty binary tree for integers can be then done as follows: - -```scala -val intLeq: (Int, Int) => Boolean = (x, y) => x <= y -val emptyIntTree: Tree[Int] = new EmptyTree(intLeq) -``` - -## Question 1 - -Given only `leq` for comparison, how can you test for equality? How about strictly-less-than? - -## Question 2 - -Define the size method on `Tree[T]`, which returns its size, i.e. the number of Nodes in the tree. - -```scala -def size: Int -``` - -Implement it in two ways: - -1. within `Tree[T]`, using pattern matching, -2. in the subclasses of `Tree[T]`. - -## Question 3 - -Define the `add` method, that adds an element to a `Tree[T]`, and returns the resulting tree: - -```scala -def add(t: T): Tree[T] = ??? -``` - -Remember that trees do not have duplicate values. If t is already in the tree, the result should be unchanged. - -## Question 4 - -Define the function `toList`, which returns the sorted list representation for a tree. For example, `emptyIntTree.add(2).add(1).add(3).toList` should return `List(1, 2, 3)` - -```scala -def toList: List[T] = ??? -``` - -You can use the `Nil` operator for creating an empty list, and the `::` operator for adding a new element to the head of a list: `1 :: List(2, 3) == List(1, 2, 3)`. You are naturally free to define any auxiliary functions as necessary. - -## Question 5 - -Define the function `sortedList`, which takes an unsorted list where no two elements are equal, and returns a new list that contains all the elements of the previous list (and only those), in increasing order. - -```scala -def sortedList[T](leq: (T, T) => Boolean, ls: List[T]): List[T] = ??? -``` - -_Hint_: you might need to define some auxiliary functions. - -## Question 6 - -If all methods are implemented using pattern matching (i.e. there are no methods implemented in subclasses), can you represent your tree type as an _ADT_ (algebraic data type) using the `enum` syntax? \ No newline at end of file diff --git a/exercises/exercise-04.md b/exercises/exercise-04.md deleted file mode 100644 index 445284a50816485a89281f72c21c1491a1e8a7af..0000000000000000000000000000000000000000 --- a/exercises/exercise-04.md +++ /dev/null @@ -1,71 +0,0 @@ -# Exercise Session 4 - -This week, we will work on the idea of variance, and on pattern matching. - -## Question 1 - -Recall that: - -- Lists are covariant in their only type parameter. -- Functions are contravariant in the argument, and covariant in the result. - -Consider the following hierarchies: - -```scala -abstract class Fruit -class Banana extends Fruit -class Apple extends Fruit -abstract class Liquid -class Juice extends Liquid -``` - -Consider also the following typing relationships for `A`, `B`, `C`, `D`: `A <: B` and `C <: D`. - -Fill in the subtyping relation between the types below. Bear in mind that it might be that neither type is a subtype of the other. - -| Left hand side | ?: | Right hand side | -| ---: | --- | :--- | -| List[Banana] | | List[Fruit] | -| List[A] | | List[B] | -| Banana => Juice | | Fruit => Juice | -| Banana => Juice | | Banana => Liquid | -| A => C | | B => D | -| List[Banana => Liquid] | | List[Fruit => Juice] | -| List[A => D] | | List[B => C] | -| (Fruit => Juice) => Liquid | | (Banana => Liquid) => Liquid | -| (B => C) => D | | (A => D) => D | -| Fruit => (Juice => Liquid) | | Banana => (Liquid => Liquid) | -| B => (C => D) | | A => (D => D) | - -## Question 2 - -The following data type represents simple arithmetic expressions: - -```scala -enum Expr: - case Number(x: Int) - case Var(name: String) - case Sum(e1: Expr, e2: Expr) - case Prod(e1: Expr, e2: Expr) -``` - -Define a function `deriv(expr: Expr, v: String): Expr` returning the expression that is the partial derivative of `expr` with respect to the variable `v`. - -```scala -def deriv(expr: Expr, v: String): Expr = ??? -``` - -Here's an example run of the function: - -```scala -> deriv(Sum(Prod(Var("x"), Var("x")), Var("y")), "x") -Sum(Sum(Prod(Var("x"), Number(1)), Prod(Number(1), Var("x"))), Number(0)) -``` - -## Question 3 - -Write an expression simplifier that applies some arithmetic simplifications to an expression. For example, it would turn the above monstrous result into the following expression: - -```scala -Prod(Var("x"), Number(2)) -``` diff --git a/exercises/exercise-05.md b/exercises/exercise-05.md deleted file mode 100644 index 4bd41495efec2e3845de92caf630c919bd0632af..0000000000000000000000000000000000000000 --- a/exercises/exercise-05.md +++ /dev/null @@ -1,73 +0,0 @@ -# Exercise Session 5 - -*Structural Induction* - -## Question 1 - -Prove that the following equivalence holds by using inductive reasoning: - -``` -alist map f map g === alist map (f andThen g) -``` - -Axioms: - - 1) `Nil map f === Nil` - 2) `(x :: xs) map f === f(x) :: (xs map f)` - 3) `(f andThen g)(x) === g(f(x))` - -**Note**: Be very precise in your proof: - -- Clearly state which axiom you use at each step, and when/if you use the induction hypothesis. -- Use only 1 axiom/hypothesis at each step, and only once. Applying 2 axioms requires 2 steps. -- Underline the part of an equation on which you apply your axiom. -- Make sure to state what you want to prove, and what your induction hypothesis is, if any. - -## Question 2 - -A more complicated proof (midterm 2016) - -We want to implement a function `sum(list: List[Int]): Int`, which returns the sum of the elements of a list of `Int`-s. We can easily *specify* that function as follows: - -``` -(1) sum(Nil) === 0 -(2) sum(x :: xs) === x + sum(xs) -``` - -If we naively translate this specification into a Scala implementation, we end up with a uselessly non-tail recursive function. Besides, doing the recursion ourselves is wasteful. Instead, we implement it using `foldLeft`: - -```scala -def betterSum(list: List[Int]): Int = - list.foldLeft(0)(add) - -def add(a: Int, b: Int): Int = a + b -``` - -However, that implementation is not trivially correct anymore. We would like to *prove* that it is correct for all lists of integers. In other words, we want to prove that - -``` -list.foldLeft(0)(add) === sum(list) -``` - -for all lists of integers. - -In addition to the specification of `sum` `(1-2)`, you may use the following axioms: - -``` -(3) Nil.foldLeft(z)(f) === z -(4) (x :: xs).foldLeft(z)(f) === xs.foldLeft(f(z, x))(f) -(5) add(a, b) === a + b -(6) a + b === b + a -(7) (a + b) + c === a + (b + c) -(8) a + 0 === a -``` - -Axioms 3-5 follow from the implementations of `foldLeft` and `add`. Axioms 6-8 encode well-known properties of `Int.+`: commutativity, associativity, and neutral element. - -**Your task**: prove the following lemma by structural induction: - -```scala -list.foldLeft(z)(add) === z + sum(list) -``` - -From that lemma, we can "trivially" (with the help of axioms 6 and 8) derive that the implementation of `betterSum` is correct by substituting `0` for `z` in the lemma. You are not asked to do that last bit. diff --git a/exercises/exercise-06.md b/exercises/exercise-06.md deleted file mode 100644 index b805f493e4ef82766faef69f51106c34aa9a0213..0000000000000000000000000000000000000000 --- a/exercises/exercise-06.md +++ /dev/null @@ -1,83 +0,0 @@ -# Exercise Session 6 - -For comprehensions and monads - -## Question 1.1 - -Consider a directed graph given by its set of (directed) edges stored as a list of pairs of nodes: - -```scala -type NodeId = Int -type DirectedEdge = (NodeId, NodeId) -type DirectedGraph = List[DirectedEdge] -``` - -Define, non-recursively, the `triangles` function that finds all cycles of length 3, with three distinct nodes, in the given graph. You should use a for comprehension. - -```scala -def triangles(edges: DirectedGraph): List[(NodeId, NodeId, NodeId)] = for ... -``` - -Each cycle should appear only once. For instance, given the edges: - -``` -List((1, 2), (2, 3), (3, 1)) -``` - -You should return exactly one of the three following possibilities: - -``` -(1, 2, 3), (2, 3, 1), (3, 1, 2) -``` - -You are free to decide which of the three you return. - - -## Question 1.2 - -After that, translate the for comprehension you wrote in the appropriate combination of `map`/`flatMap`/`filter` calls. - - -## Question 2. - -Monads are often defined with a `map` method in addition to `flatMap`: - -```scala -trait M[T] { - def flatMap[U](f: T => M[U]): M[U] - def map[U](f: T => U): M[U] -} -``` - -Where `map` and `flatMap` are related by the following law: - -``` -Monad/Functor Consistency: -m.map(f) === m.flatMap(x => unit(f(x))) -``` - -We introduce you a new algebraic structure called `Functor`-s. We say that a `type F` is a `Functor` if `F[T]` has a `map` method with the following signature: - -```scala -trait F[T] { - def map[U](f: T => U): F[U] -} -``` - -And there is a `unit` method for `F` with the following signature: - -```scala -def unit[T](x: T): F[T] -``` - -Such that `map` and `unit` fulfill the following laws: - -``` -Identity: -m.map(x => x) === m - -Associativity: -m.map(h).map(g) === m.map(x => g(h(x))) -``` - -Prove that any `Monad` with a `map` method that fulfills the `Monad/Functor Consistency` law is also a `Functor`. diff --git a/exercises/exercise-07.md b/exercises/exercise-07.md deleted file mode 100644 index 5ab1f58785c5a5be4d95ea39a8e0f88f4e65243f..0000000000000000000000000000000000000000 --- a/exercises/exercise-07.md +++ /dev/null @@ -1,62 +0,0 @@ -# Exercise Session 7 - -## Question 1 - -Consider the following series: - -``` -1 -1 1 -2 1 -1 2 1 1 -1 1 1 2 2 1 -3 1 2 2 1 1 -........... -``` - -1. Find the next element in the sequence above. - -Now, let us encode an element of the sequence above as a `List[Int]`. - - -2. Write a function to compute the next element. - -```scala -def nextLine(currentLine: List[Int]): List[Int] = ??? -``` - -3. Implement a lazy list `funSeq` which constructs this sequence. Recall: to construct a lazy list, you can use `LazyList.cons[A](a: A, b: => LazyList[A]): LazyList[A]` - -```scala -lazy val funSeq: LazyList[List[Int]] = ... -``` - -## Question 2 - -1. Write a lazy list of squares of integers ≥ 1. You may use `LazyList.from(i: Int)` - -```scala -val squares: LazyList[Int] = ... -``` - -2. Write a lazy list of all non-empty strings using the characters "0" and "1" and the concatenation operation +. In other words, every non-empty string composed of "0" and "1" should be reached at some point. - -```scala -val codes: LazyList[String] = ... -``` - -3) Using `codes`, write a lazy list of all possible non-empty palindromes of "0" and "1". You may use the `.reverse` function defined on strings. - -```scala -val palCodes: LazyList[String] = ... -``` - -4. Can you do the same without filtering? The palindromes need not to be in the same order. - -5. Given another lazy list `otherCodes`, possibly finite or infinite, you don't know at first: - -```scala -val otherCodes: LazyList[String] = [some external source] -``` - -Build a lazy list `allCodes` that interleaves `palCodes` and `otherCodes`. diff --git a/exercises/exercise-08.md b/exercises/exercise-08.md deleted file mode 100644 index 20ce180c50e473c883563909a829a72fd86cfd48..0000000000000000000000000000000000000000 --- a/exercises/exercise-08.md +++ /dev/null @@ -1,152 +0,0 @@ -# Exercise Session 8 - -## Question 1 - -In this exercise, we will define instances of the `Eq` type class. -Recall the `Ordering[A]` type class introduced in the lecture. -An instance of `Ordering[A]` allows us to compare values of type `A` -to see which one (if any) is smaller. -Similarly, an instance of `Eq[A]` allows us to compare values of type `A` to see if they are equal. -We can define it as follows: - -```scala -trait Eq[T]: - extension (x: T) - def === (y: T): Boolean -``` - -### Question 1.1 - -Write a `given` instance to create `Eq[List[T]]` from a `Eq[T]`. - - -### Question 1.2 - -Write a `given` instance to create `Eq[(T, U, S)]` from `Eq[T]`, `Eq[U]` and `Eq[S]`. - -### Question 1.3 - -Write `given` instance to create `Eq[Person]`. Make use of both the definitions you have written previously. - -```scala -case class Person(name: String, age: Int, neighbours: List[String]) -``` - -### Question 1.4 - -Explicitly write the `using` argument to `summon` (you may need to assign names to your `given` definitions): - -```scala -summon[Eq[Person]](using ...) -``` - -## Question 2 - -In this exercise, we will use term inference to calculate types based on other types. - -First, we define `Nat`: - -```scala -trait Nat - -/** Zero */ -case object Z extends Nat -type Z = Z.type - -/** The Successor of N */ -case class S[N <: Nat](pred: N) extends Nat -``` - -`Nat` encodes natural numbers on the type level: - -```scala -S(S(Z)) -// res0: S[S[Z]] = S(S(Z)) -``` - -The type `S[S[Z]]` represents the successor of the successor of zero: two. - -We can add two values of type `Nat` as follows: - -```scala -def add1(n: Nat, m: Nat): Nat = - n match - case Z => m - case S(n1) => S(add1(n1, m)) -``` - -However, this definition has an issue: the result is imprecisely typed: - -```scala -add1(S(Z), S(Z)) -// res1: Nat = S(S(Z)) -``` - -To fix this, we will define the `Sum[N, M, R]` type class. An instance of Sum represents evidence that `N + M = R`. - -With the appropriate given definitions, the compiler can infer an instance of `Sum[N, M, R]` such that `N + M = R`, for any pair of natural numbers `N` and `M`: - -```scala -case class Sum[N <: Nat, M <: Nat, R <: Nat](result: R) - -given zero: Z = Z -given succ[N <: Nat](using n: N): S[N] = S(n) - -given sumZ[N <: Nat](using n: N): Sum[Z, N, N] = Sum(n) - -given sumS[N <: Nat, M <: Nat, R <: Nat]( - using sum: Sum[N, M, R] -): Sum[S[N], M, S[R]] = Sum(S(sum.result)) -``` - -Note how the last two `given` definitions reflect the definition of the `add1` method: `sumZ` corresponds to the case for `Z + M`, and `sumS` corresponds to the case for `S[N] + M`. The second case is recursive, explicitly for `add1` and using term inference for the `given` definition. - -Using the above definitions, we can write a function that adds two `Nat` -values and assigns a precise type to the result: - -```scala -def add[N <: Nat, M <: Nat, R <: Nat](n: N, m: M)( - using sum: Sum[N, M, R] -): R = sum.result -``` - -As an example, the result of adding `S(Z)` to `S(Z)` is now precisely typed as `S[S[Z]]`: - -```scala -add(S(Z), S(Z)) -// res2: S[S[Z]] = S(S(Z)) -``` - -### Question 2.1 - -Write explicitly the `using` argument to `sum` (it may help to write all type parameters explicitly): - -```scala -add(S(Z), S(S(Z)))(using ...) -``` - -*Note:* If you try this in the Scala 3 compiler right now, the result won't be correct, -this is a known compiler bug: https://github.com/lampepfl/dotty/issues/7586. - -### Question 2.2 - -Write `given` definitions that create an instance of the -`Product[N, M, R]` type class, representing the evidence that `N * M = R`. - -```scala -case class Product[N <: Nat, M <: Nat, R <: Nat](result: R) -``` - -Hint 1: Multiplying two natural numbers is defined as follows: - -```scala -def mul1(n: Nat, m: Nat): Nat = - n match - case Z => Z - case S(n1) => add1(m, mul1(n1, m)) -``` - -Hint 2: The `R` type parameter is key to making the `add` definition work. -When we start inferring a term of type `Sum[N, M, R]`, we already know what -`N` and `M` are, but we don't know what `R` is. Inferring the term will also -infer the type that stands for `R`. diff --git a/exercises/exercise-09.md b/exercises/exercise-09.md deleted file mode 100644 index 8975cfa603bcc9477931baaf8267fab8163fc8f3..0000000000000000000000000000000000000000 --- a/exercises/exercise-09.md +++ /dev/null @@ -1,85 +0,0 @@ -# Exercise Session 9 - -## Question 1 - -Implement a function `groupBy` by yourself, without using the standard `groupBy` method: - -```scala -def groupBy[T, S](f: T => S)(xs: List[T]): Map[S, List[T]] = ??? -``` - -Write two versions: - -- One using a mutable `var` and a `foreach` loop. -- One using `foldRight`. - -## Question 2 - -### Question 2.1 - -When running code, it can be useful to print what is going on for debugging. In order to do so, let us define a trait `Logger`: - -```scala -trait Logger: - def log(message: String): Unit -``` - -Implement a `LoggerBuffered` what will accumulate messages in a private `buffer` mutable field. - -```scala -class LoggerBuffered extends Logger: - def log(message: String): Unit = ??? - def getOutput(): String = ??? -``` - -### Question 2.2 - -Remember the `eval` function from the midterm exam. A possible implementation would be the following: - -```scala -enum Expr: - case Var(name: String) - case Op(name: String, args: List[Expr]) - -import Expr._ - -final case class UnknownVarException(name: String) extends Exception -final case class UnknownOpException(name: String) extends Exception - -def eval(e: Expr, context: Map[Var, Int]): Int = e match - case sym: Var if context.contains(sym) => context(sym) - case sym: Var => throw UnknownVarException(sym.name) - case Op("*", args) => args.map(eval(_, context)).foldLeft(1)(_ * _) - case Op("+", args) => args.map(eval(_, context)).foldLeft(0)(_ + _) - case Op(name, _) => throw UnknownOpException(name) -``` - -Write a new version that will log the evaluation steps to a logger implicitly passed as argument: - - -```scala -def evalTracing(e: Expr, context: Map[Var, Int])(using logger: Logger): Int = ??? -``` - -When reading a value, it should log `Get var [name] = [value] from the context`. When applying an operation, it should log `Apply operation [name] to arguments [args]`, where `[args]` is a comma-separated list of evaluated arguments. - - -Example run: - -```scala -given logger: LoggerBuffered = LoggerBuffered() - -evalTracing( - Op("*", List(Var("x"), Op("+", List(Var("y"), Var("z"))))), - Map(Var("x") -> 2, Var("y") -> 3, Var("z") -> 4) -) -// res3: Int = 14 - -logger.getOutput() -// res4: String = """Get var x = 2 from the context.\n -// Get var y = 3 from the context.\n -// Get var z = 4 from the context.\n -// Apply operation + to arguments 3,4 -// Apply operation * to arguments 2,7 -// """ -``` \ No newline at end of file diff --git a/exercises/exercise-10.md b/exercises/exercise-10.md deleted file mode 100644 index 28663b8d86049b0009cdbb4c3b438153f39917ab..0000000000000000000000000000000000000000 --- a/exercises/exercise-10.md +++ /dev/null @@ -1,135 +0,0 @@ -# Exercise Session 10 - -## Question 1 - -For this exercise, you are given the following ASTs representing an expression `Expr` - -```scala -enum BinOpName: - case Minus - case Plus - case Times - case LessEq - case Modulo - -enum Expr: - case Constant(value: Int) // Numeric constants - case Name(name: String) // reference to a name - case BinOp(op: BinOpName, arg1: Expr, arg2: Expr) // primitive binary operation - case IfNonzero(cond: Expr, caseTrue: Expr, caseFalse: Expr) // conditional - case Call(function: Expr, arg: Expr) // function call - case Fun(param: String, body: Expr) // function definition // function definition - -import BinOpName._ -import Expr._ -``` - -We also provide a few valid primitive operations that you may use - -```scala -def minus(e1: Expr, e2: Expr) = BinOp(Minus, e1, e2) -def plus(e1: Expr, e2: Expr) = BinOp(Plus, e1, e2) -def leq(e1: Expr, e2: Expr) = BinOp(LessEq, e1, e2) // 1 if e1 <= e2; 0 otherwise // 1 if e1 <= e2; 0 otherwise -def times(e1: Expr, e2: Expr) = BinOp(Times, e1, e2) -def modulo(e1: Expr, e2: Expr) = BinOp(Modulo, e1, e2) -``` - -The global environment is a sequence of `"name" -> definition` tuples (of type `(String, Expr)`). -All definitions can reference all names in the global environment. - -Where for example one could define a division function `div` as follows: - -```scala -"div" -> Fun("x", Fun("y", - IfNonzero(BinOp(LessEq, Name("y"), Name("x")), - plus(Constant(1), - Call(Call(Name("div"), minus(Name("x"), Name("y"))), - Name("y"))), - Constant(0)))) -``` - - -Your task is to implement the greatest common divisor (`gcd`) function in `Expr`. - -```scala -"gcd" -> ??? // TODO implement me -``` - -Hint: in Scala the `gcd` can be implemented as -```scala -def gcd(a: Int, b: Int): Int = if b == 0 then a else gcd(b, a%b) -``` - -## Question 2 - -For this exercise, we will add lists to our language - -```scala -enum Expr: - ... - case Cons(head: Expr, tail: Expr) // Cons list - case EmptyList // empty of a Cons list - // matches a list - case Match(scrutinee: Expr, caseEmpty: Expr, headName: String, tailName: String, caseCons: Expr) -``` - -For example, the following program a match in Scala would translate as - -```scala -ls match - case Nil => Nil - case x :: xs => x :: xs -// becomes -Match(Name("ls"), - EmptyList, - "x", "xs", Cons(Name("x"), Name("xs")) -) -``` - - -### Map -Your task is to implement the `map` function in `Expr`. - -Hint: -```scala -def map(ls: List[Int])(f: Int => Int): List[Int] = ls match - case Nil => Nil - case x :: xs => f(x) :: map(xs)(f) -``` - - -### Fold Left -Your task is to implement the `foldLeft` function in `Expr`. -Hint: -```scala -def foldLeft(ls: List[Int])(acc: Int)(f: (Int, Int) => Int): Int = ls match - case Nil => acc - case x :: xs => foldLeft(xs)(f(acc, x))(f) -``` - -## Question 3 - -For this exercise, we will add writable cells to our language. Assume we have a global array of memory that can be accessed by index. -```scala -enum Expr: - ... - // read from position `idx` - case Read(idx: Expr) - // write the `value` to position `idx` and then evaluates and return the `andThen` expression - case Write(idx: Expr, value: Expr, andThen: Expr) -end Expr -``` - - -Your task is to implement the `CAS` (compare and swap) function in `Expr`. - -Hint: -```scala -val mem: Array[Int] = ??? -def CAS(idx: Int)(old: Int)(nw: Int): Int = - if mem(idx) != old then - 0 - else - mem(idx) = nw - 1 -``` diff --git a/exercises/exercise-11.md b/exercises/exercise-11.md deleted file mode 100644 index f2ffd566dc59b1b5127380ebfc9819b87b63db39..0000000000000000000000000000000000000000 --- a/exercises/exercise-11.md +++ /dev/null @@ -1,69 +0,0 @@ -# Exercise Session 11 - -In these exercises, you are asked to write higher-order functions in the simple untyped language supported by the interpreter for recursive higher-order functions that we developed in the lectures. - -## Question 1 - -In this exercise, you will be working with _Church numerals_. - -Church numerals are a representation of natural numbers using only functions. -In this encoding, a number `n` is represented by a function that maps any function `f` to its `n`-fold composition. - -For example, `0`, `1`, `2` and `3` are represented as follows: - -```scala -def zero = (f => x => x) -def one = (f => x => f x) -def two = (f => x => f (f x)) -def three = (f => x => f (f (f x))) -``` - -### Question 1.1 - -Give an implementation of the `succ` function that takes a Church numeral and returns its successor. - -For example, `(succ zero)` evaluates to the definition of `one` and `(succ one)` evaluates to the definition of `two`. - -### Question 1.2 - -Give an implementation of the `add` function that takes two Church numerals and returns their sum, using `succ`. - -## Question 2 - -In this exercise, you will be working with _Church-encoded lists_. - -Much like Church numerals, Church-encoded lists are a representation of lists using only functions. - -In this encoding, a list is represented by a function that takes two arguments and -returns the first one if the list is empty or returns the second one applied to head and tail if the list is non-empty: - -```scala -def nil = (n => c => n) -def cons = (h => t => - n => c => c h t) -``` - -For example, `List(1,2,3)` would be represented in this encoding as follows: - -```scala -(cons 1 (cons 2 (cons 3 nil))) -``` - -With Church-encoded lists, decomposition is achieved by "applying" the list to a pair of continuations, one for the empty case and another one for the non-empty case. For example, concatenation of two Church-encoded lists could be implemented as follows: - -```scala -def cat = (l1 => l2 => - (l1 l2 (h => t => (cons h (cat t l2)))) -``` - -### Question 2.1 - -Give an implementation of the `size` function that takes a Church-encoded list and returns its size as a Church numeral. You are allowed to use the `succ` function defined earlier. - -### Question 2.2 - -Give an implementation of the `map` function which takes a Church-encoded list and a function and returns the list mapped with the function (in the sense of `List.map`). You may use recursion in your definitions. - -### Question 2.3 - -Give an implementation of the `foldRight` function which takes a Church-encoded list and a function and returns the result of `foldRight`. You may use recursion in your definitions. diff --git a/exercises/solution-01.md b/exercises/solution-01.md deleted file mode 100644 index 6d321bbeb8ceebee426406860983c1be5440b5ee..0000000000000000000000000000000000000000 --- a/exercises/solution-01.md +++ /dev/null @@ -1,67 +0,0 @@ -# Exercise Session 1, Solutions - -## Question 1: Factorial - -```scala -import scala.annotation.tailrec - -def factorial(n: Int) = - require(n >= 0) - - @tailrec - def loop(n: Int, acc: Int): Int = - if n == 0 then acc - else loop(n - 1, acc * n) - - loop(n, 1) -``` - -## Question 2: Sum of elements on a list - -```scala -import scala.annotation.tailrec - -def sumList(ls: List[Int]) = - @tailrec - def loop(ls: List[Int], acc: Int): Int = - if ls.isEmpty then acc - else loop(ls.tail, acc + ls.head) - - loop(ls, 0) -``` - -## Question 3: Fast exponentiation - -```scala -import scala.annotation.tailrec - -def fastExp(base: Int, exp: Int): Int = - require(exp >= 0) - - @tailrec - def loop(base: Int, exp: Int, acc: Int): Int = - if exp == 0 then - acc - else if (exp % 2) != 0 then - loop(base, exp - 1, base * acc) - else - loop(base * base, exp / 2, acc) - - loop(base, exp, 1) -``` - -## Question 4: Tail recursive Fibonacci - -```scala -import scala.annotation.tailrec - -def fibonacci(n: Int): Int = - require(n >= 0) - - @tailrec - def loop(k: Int, previous: Int, current: Int): Int = - if k == n then current - else loop(k + 1, current, previous + current) - - if n == 0 then 0 else loop(1, 0, 1) -``` diff --git a/exercises/solution-02.md b/exercises/solution-02.md deleted file mode 100644 index b8857deb591de8fbfed61c9997f61d5cd852014a..0000000000000000000000000000000000000000 --- a/exercises/solution-02.md +++ /dev/null @@ -1,118 +0,0 @@ -# Exercise Session 2, Solutions - -## Question 1 - -```scala -def flip(f: (Double, Int) => Boolean): (Int, Double) => Boolean = - (x1: Int, x2: Double) => f(x2, x1) -``` - -## Question 2 - -### Question 2.1 - -```scala -val id: Int => Int = (x: Int) => x -``` - -### Question 2.2 - -```scala -def compose(f: Int => Int, g: Int => Int): Int => Int = - (x: Int) => f(g(x)) -``` - -`compose(id, f)(k)` evaluates to `f(k)`, as does `compose(f, id)(k)`. - -More generally (see ["Identity Function" on Wikipedia](https://en.wikipedia.org/wiki/Identity_function#Algebraic_properties)): - -> If f: M → N is any function, then we have f ∘ id<sub>M</sub> = f = id<sub>N</sub> ∘ f. - -### Question 2.3 - -```scala -def repeated(f: Int => Int, n: Int): Int => Int = - if n == 0 then identity - else compose(f, repeated(f, n-1)) -``` - -## Question 3 - -### Question 3.1 - -```scala -def curry2(f: (Double, Int) => Boolean): Double => (Int => Boolean) = - (x1: Double) => (x2: Int) => f(x1, x2) -``` - -### Question 3.2 - -```scala -def uncurry2(f: Double => Int => Boolean): (Double, Int) => Boolean = - (x1: Double, x2: Int) => f(x1)(x2) -``` - -## Question 4 - -```scala -import scala.annotation.tailrec - -def fixedPoint(f: Int => Int): Int => Int = - @tailrec - def loop(guess: Int): Int = - val image: Int = f(guess) - if image == guess then guess else loop(image) - loop -``` - -Or alternatively, using currying: - -```scala -def fixedPointCurry(f: Int => Int)(guess: Int): Int = - val image: Int = f(guess) - if image == guess then guess else fixedPoint(f)(image) -``` - -- `fixedPoint(x => x/2)(4)` returns `0`. -- `fixedPoint(id)(123456)` returns `123456`. -- `fixedPoint(x => x + 1)(0)` does not terminate. -- `fixedPoint(x => if (x % 10 == 0) x else x + 1)(35)` returns `40`. -- `fixedPoint(x => x / 2 + 5)(20)` returns `10`. - -## Question 5 - -### Question 5.1 - -As seen in [the slides](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/slides/progfun1-2-2.pdf): - -```scala -def sum(f: Int => Int)(a: Int, b: Int): Int = - if a > b then 0 else f(a) + sum(f)(a + 1, b) -``` - -Tail-recursive version: - -```scala -import scala.annotation.tailrec - -def sumTailRec(f: Int => Int)(a: Int, b: Int): Int = - @tailrec - def loop(i: Int, acc: Int): Int = - if i > b then acc else loop(i + 1, acc + f(i)) - - loop(a, 0) -``` - -### Question 5.2 - -```scala -def quadratic(c: Int): Int => Int = - (x: Int) => (x - c) * (x - c) -``` - -### Question 5.3 - -```scala -val quad3Integrate: (Int, Int) => Int = - sum(quadratic(3)) -``` diff --git a/exercises/solution-03.md b/exercises/solution-03.md deleted file mode 100644 index 3bde1f15dfa5e7f3cbde6540a2de8ea7ab36d8b0..0000000000000000000000000000000000000000 --- a/exercises/solution-03.md +++ /dev/null @@ -1,94 +0,0 @@ -# Exercise Session 3, Solutions - -## Question 1 - -```scala -def eq[T](a: T, b: T, leq: (T, T) => Boolean) = leq(a, b) && leq(b, a) -def le[T](a: T, b: T, leq: (T, T) => Boolean) = !leq(b, a) -``` - -## Question 2 - -Using pattern matching: - -```scala -trait Tree[T]: - def size: Int = this match - case EmptyTree(_) => 0 - case Node(left, _, right, _) => left.size + 1 + right.size - -case class EmptyTree[T](leq: (T, T) => Boolean) extends Tree[T] -case class Node[T](left: Tree[T], elem: T, right: Tree[T], leq: (T, T) => Boolean) extends Tree[T] -``` - -Defining a method per subclass: - -```scala -trait Tree[T]: - def size: Int - -case class EmptyTree[T](leq: (T, T) => Boolean) extends Tree[T]: - def size: Int = 0 - -case class Node[T](left: Tree[T], elem: T, right: Tree[T], leq: (T, T) => Boolean) extends Tree[T]: - def size: Int = left.size + 1 + right.size - -``` - -## Question 3 - -```scala -def add(newElem: T): Tree[T] = this match - case EmptyTree(leq) => - Node(EmptyTree(leq), newElem, EmptyTree(leq), leq) - case Node(left, elem, right, leq) => - if leq(newElem, elem) then - if leq(elem, newElem) then this - else Node(left.add(newElem), elem, right, leq) - else Node(left, elem, right.add(newElem), leq) -``` - -## Question 4 - -```scala -def toList: List[T] = - def toListAcc(tree: Tree[T], acc: List[T]): List[T] = tree match - case EmptyTree(_) => acc - case Node(left, elem, right, _) => - toListAcc(left, elem :: toListAcc(right, acc)) - - toListAcc(this, Nil) -``` - -Without using an accumulator: - -```scala -def toListNoAcc: List[T] = this match - case EmptyTree(_) => Nil - case Node(left, elem, right, _) => - (left.toList :+ elem) ++ right.toList - // shortand for left.toList.appended(elem).concat(right.toList) -``` - -## Question 5 - -```scala -def sortedList[T](leq: (T, T) => Boolean, ls: List[T]): List[T] = - def buildTree(elems: List[T], acc: Tree[T]): Tree[T] = elems match - case Nil => acc - case elem :: rest => buildTree(rest, acc.add(elem)) - - buildTree(ls, EmptyTree(leq)).toList -``` - -## Question 6 - -```scala -enum Tree[T]: - def size: Int = /* ... */ - def add(newElem: T): Tree[T] = /* ... */ - def toList: List[T] = /* ... */ - - case EmptyTree(leq: (T, T) => Boolean) - case Node(left: Tree[T], elem: T, right: Tree[T], leq: (T, T) => Boolean) -``` \ No newline at end of file diff --git a/exercises/solution-04.md b/exercises/solution-04.md deleted file mode 100644 index 37f5ee87cd46c6f28ba1cefa7b48811ac3996882..0000000000000000000000000000000000000000 --- a/exercises/solution-04.md +++ /dev/null @@ -1,58 +0,0 @@ -# Exercise Session 4, Solutions - -## Question 1 - -| Left hand side | ?: | Right hand side | -| ---: | --- | :--- | -| List[Banana] | <: | List[Fruit] | -| List[A] | <: | List[B] | -| Banana => Juice | >: | Fruit => Juice | -| Banana => Juice | <: | Banana => Liquid | -| A => C | X | B => D | -| List[Banana => Liquid] | >: | List[Fruit => Juice] | -| List[A => D] | >: | List[B => C] | -| (Fruit => Juice) => Liquid | >: | (Banana => Liquid) => Liquid | -| (B => C) => D | >: | (A => D) => D | -| Fruit => (Juice => Liquid) | X | Banana => (Liquid => Liquid) | -| B => (C => D) | X | A => (D => D) | - -## Question 2 - -```scala -def deriv(e: Expr, v: String): Expr = e match - case Number(_) => Number(0) - case Var(name) => if name == v then Number(1) else Number(0) - case Sum(left, right) => Sum(deriv(left, v), deriv(right, v)) - case Prod(left, right) => - Sum(Prod(deriv(left, v), right), Prod(left, deriv(right, v))) -``` - -## Question 3 - -```scala -def simplify(expr: Expr): Expr = expr match - case Number(_) => expr - case Var(_) => expr - case Sum(a, b) => - (simplify(a), simplify(b)) match - case (Number(x), Number(y)) => Number(x + y) - case (Number(0), y) => y - case (x, Number(0)) => x - case (x, y) => if x == y then Prod(Number(2), x) else Sum(x, y) - case Prod(a, b) => - (simplify(a), simplify(b)) match - case (Number(x), Number(y)) => Number(x * y) - case (Number(0), _) => Number(0) - case (_, Number(0)) => Number(0) - case (Number(1), y) => y - case (x, Number(1)) => x - case (x, y) => Prod(x, y) -``` - -Note that this is a pretty open question. The above solution is still incapable of simplifying `Sum(Number(1), Sum(Var("x"), Number(2))) into Sum(Number(3), Var("x"))`, which is disappointing. Can you imagine ways to improve it? - -**Idea for further exercise**: - -Implement a `simplify` function which will completely simplify all expressions given to it. - -_Hint_: Instead of trying to add more special cases in the above function, try to convert the expression into some kind of normalized form. For instance, this normalized form could be a sum of products (of numbers and variables), represented as a list of lists of expressions. Then, you could apply simplifications on this normalized form. Finally, you would have to reconstruct a single expression out of it. diff --git a/exercises/solution-05.md b/exercises/solution-05.md deleted file mode 100644 index 207bc273be2ffd03de0c52ad9ee2a34544668a8a..0000000000000000000000000000000000000000 --- a/exercises/solution-05.md +++ /dev/null @@ -1,51 +0,0 @@ -# Exercise Session 5, Solutions - -## Question 2 - -**To prove**: - -We want to prove `P(list)` for any list of type `List[Int]`, where `P(list)` is defined as: - -```scala -P(list) := list.foldLeft(z)(add) === z + sum(list), for all z of type Int -``` - -The proof proceeds by structural induction on `list`. - -**Case Nil**: - -We want to show `P(Nil)`. -Let `z` be an arbitrary expression of type `Int`. - -``` -sNil.foldLeft(z)(add) === (by 3) z - === (by 8) z + 0 - === (by 1) z + sum(Nil) -``` - -Which proves `P(Nil)`. - -**Case x :: xs**: - -We want to show `P(x :: xs)`, assuming `P(xs)`. - -Induction hypothesis: `P(xs)` - -``` -(IH) xs.foldLeft(z')(add) === z' + sum(xs), for all z' of type Int -``` - -Let `z` be an arbitrary expression of type `Int`. - -``` -(x :: xs).foldLeft(z)(add) - === (by 4) xs.foldLeft(add(z, x))(add) - === (by IH) add(z, x) + sum(xs) - === (by 5) (z + x) + sum(xs) - === (by 7) z + (x + sum(xs)) - === (by 2) z + sum(x :: xs) -``` - -Which proves `P(x :: xs)`. - -This completes the proof. diff --git a/exercises/solution-06.md b/exercises/solution-06.md deleted file mode 100644 index cc8dd02b6e7922e608ad7ab2d3eed85d7e3f3d32..0000000000000000000000000000000000000000 --- a/exercises/solution-06.md +++ /dev/null @@ -1,76 +0,0 @@ -# Exercise Session 6, Solutions - -## Question 1.1 - -```scala -// For equivalent cycles, we decide to return the cycle -// with the smallest element first. -def triangles(edges: DirectedGraph): List[(NodeId, NodeId, NodeId)] = - for { - e1 <- edges - - // The first node is the smallest of the cycle. - if (e1._1 < e1._2) - - e2 <- edges - - // The two edges are connected and - // there exists an edge between the two other end points. - if (e1._2 == e2._1 && edges.contains((e2._2, e1._1))) - - // The first node is the smallest of the cycle. - if (e1._1 < e2._2 && e2._1 != e2._2) - - } yield (e1._1, e1._2, e2._2) -``` - -An alternative solution using case extractors and references to previous values -```scala -def triangles(edges: DirectedGraph): List[(NodeId, NodeId, NodeId)] = - for { - case (a, b) <- edges; - if a < b; // The first node is the smallest of the cycle. - case (`b`, c) <- edges; - if a < c; - case (`c`, `a`) <- edges; - } yield (a, b, c) -``` - -## Question 1.2 - -```scala -def triangles(edges: DirectedGraph): List[(NodeId, NodeId, NodeId)] = - edges.filter { e1 => - e1._1 < e1._2 - }.flatMap { e1 => - edges.filter { e2 => - e1._2 == e2._1 && edges.contains((e2._2, e1._1)) - }.filter { e2 => - e1._1 < e2._2 && e2._1 != e2._2 - }.map { e2 => - (e1._1, e1._2, e2._2) - } - } -``` - -## Question 2. - -*Identity.* - -```scala - m.map(x => x) -== m.flatMap(x => unit((x => x)(x))) // Monad/Functor Consistency -== m.flatMap(x => unit(x)) // Simplification -== m.flatMap(unit) // Simplification -== m // Right unit -``` - -*Associativity.* - -```scala - m.map(h).map(g) -== m.flatMap(x => unit(h(x))).flatMap(x => unit(g(x))) // M/F Consistency -== m.flatMap(x => unit(h(x)).flatMap(x => unit(g(x)))) // Associativity -== m.flatMap(x => unit(g(h(x)))) // Left unit -== m.map(x => g(h(x))) // M/F Consistency -``` diff --git a/exercises/solution-07.md b/exercises/solution-07.md deleted file mode 100644 index 12deb5c6f49ca472108743c4fac697c279f53a30..0000000000000000000000000000000000000000 --- a/exercises/solution-07.md +++ /dev/null @@ -1,74 +0,0 @@ -# Exercise Session 7, Solutions - -## Question 1 - -1. - -```scala -1 3 1 1 2 2 2 1 -``` - -2. - -```scala -def nextLine(currentLine: List[Int]): List[Int] = { - currentLine.foldLeft(List.empty[Int]) { (acc, x) => - acc match { - case y :: count :: rest if x == y => x :: (count + 1) :: rest - case _ => x :: 1 :: acc - } - }.reverse -} -``` - -3. - -```scala -lazy val funSeq: LazyList[List[Int]] = - LazyList.cons(List(1), funSeq.map(nextLine)) -``` - -## Question 2 - -1. - -```scala -val squares: LazyList[Int] = LazyList.from(1).map(x => x * x) -``` - -2. - -```scala -lazy val codes: LazyList[String] = "0" #:: "1" #:: codes.flatMap { - (s: String) => (s + "0") #:: (s + "1") #:: LazyList.empty[String] -} -``` - -3. - -```scala -def isPalindrome(x: String): Boolean = x.reverse == x -val palCodes: LazyList[String] = codes.filter(isPalindrome) -``` - -4. - -```scala -val palCodes: LazyList[String] = for { - c <- codes - middle <- Seq("", "0", "1") -} yield c + middle + c.reverse -``` - -5. - -```scala -def interleave[A](xs: LazyList[A], ys: LazyList[A]): LazyList[A] = - (xs, ys) match { - case (x #:: xr, y #:: yr) => x #:: y #:: interleave(xr, yr) - case (LazyList.Empty, _) => ys - case (_, LazyList.Empty) => xs - } - -val allCodes = interleave(palCodes, otherCodes) -``` diff --git a/exercises/solution-08.md b/exercises/solution-08.md deleted file mode 100644 index c22cffc8902f529568f3f46b19a59ead165fe92d..0000000000000000000000000000000000000000 --- a/exercises/solution-08.md +++ /dev/null @@ -1,96 +0,0 @@ -# Exercise Session 8, Solutions - -## Question 1 - - -### Question 1.1 - -```scala -given EqList[T](using Eq[T]): Eq[List[T]] with - extension (x: List[T]) - def === (y: List[T]): Boolean = - (x, y) match - case (hx :: tx, hy :: ty) => hx === hy && tx === ty - case (Nil, Nil) => true - case _ => false -``` - -### Question 1.2 - -```scala -given EqTriple[T, U, S](using Eq[T], Eq[U], Eq[S]): Eq[(T, U, S)] with - extension (x: (T, U, S)) - def === (y: (T, U, S)): Boolean = - x._1 === y._1 && x._2 === y._2 && x._3 === y._3 -``` - -### Question 1.3 - - -```scala -given EqString: Eq[String] with - extension (x: String) - def === (y: String) = x == y - -given EqInt: Eq[Int] with - extension (x: Int) - def === (y: Int) = x == y - -given EqPerson(using Eq[(String, Int, List[String])]): Eq[Person] with - extension (a: Person) - def === (b: Person) = - (a.name, a.age, a.neighbours) === (b.name, b.age, b.neighbours) -``` - -### Question 1.4 - -```scala -summon[Eq[Person]](using - EqPerson(using - EqTriple(using - EqString, - EqInt, - EqList(using EqString) - ) - ) -) -``` - -## Question 2 - - -### Question 2.1 - -```scala -add(S(Z), S(S(Z)))(using - sumS(using - sumZ(using - succ(using - succ(using - zero - ) - ) - ) - ) -) -// res1: S[S[S[Z]]] = S(S(S(Z))) -``` - -*Note:* If you try to just write `add(S(Z), S(S(Z)))` without explictly specifying the implicit parameters in the Scala 3 compiler right now, you well get the wrong result. This is a known compiler bug: https://github.com/lampepfl/dotty/issues/7586. - - - -### Question 2.2 - -```scala -given [N <: Nat]: Prod[Z, N, Z] = Prod(Z) -given [N <: Nat, M <: Nat, R1 <: Nat, R2 <: Nat](using - prod: Prod[N, M, R1], - sum: Sum[R1, M, R2] -): Prod[S[N], M, R2] = - Prod(sum.result) - -def prod[N <: Nat, M <: Nat, R <: Nat](n: N, m: M)( - using prod: Prod[N, M, R] -): R = prod.result -``` diff --git a/exercises/solution-09.md b/exercises/solution-09.md deleted file mode 100644 index 76704aa65463c7fac85bf9555c174ae40d712a56..0000000000000000000000000000000000000000 --- a/exercises/solution-09.md +++ /dev/null @@ -1,65 +0,0 @@ -# Exercise Session 9, Solutions - -## Question 1 - -```scala -def groupBy[T, S](f: T => S)(xs: List[T]): Map[S, List[T]] = - var acc = Map[S, List[T]]() - xs.reverse.foreach(el => - val key = f(el) - val prevValue = acc.getOrElse(key, List()) - acc = acc.updated(key, el :: prevValue) - ) - acc -``` - -```scala -def groupBy2[T, S](f: T => S)(xs: List[T]): Map[S, List[T]] = - xs.foldRight(Map[S, List[T]]())((el: T, acc: Map[S, List[T]]) => - val key = f(el) - val prevValue = acc.getOrElse(key, List()) - acc.updated(key, el :: prevValue) - ) -``` - -Example run: - -```scala -groupBy[Int, Int](_ % 3)((0 to 10).toList) -// res0: Map[Int, List[Int]] = Map( -// 1 -> List(1, 4, 7, 10), -// 0 -> List(0, 3, 6, 9), -// 2 -> List(2, 5, 8) -// ) -``` - -## Question 2 - -### Question 2.1 - - -```scala -class LoggerBuffered extends Logger: - private var output: String = "" - def log(message: String): Unit = output = output + message + "\n" - def getOutput(): String = output -``` - -### Question 2.2 - - -```scala -def evalTracing(e: Expr, context: Map[Var, Int])(using logger: Logger): Int = e match - case sym: Var if context.contains(sym) => - val value = context(sym) - logger.log(f"Get var ${sym.name} = ${value} from the context.\n") - value - case sym: Var => throw UnknownVarException(sym.name) - case Op(name, args) => - val evaluatedArgs= args.map(evalTracing(_, context)) - logger.log(f"Apply operation ${name} to arguments ${evaluatedArgs.mkString(",")}") - name match - case "*" => evaluatedArgs.foldLeft(1)(_ * _) - case "+" => evaluatedArgs.foldLeft(0)(_ + _) - case _ => throw UnknownOpException(name) -``` \ No newline at end of file diff --git a/exercises/solution-10.md b/exercises/solution-10.md deleted file mode 100644 index df8a687d61e8785ef1fa7afd27d52d4f4613d759..0000000000000000000000000000000000000000 --- a/exercises/solution-10.md +++ /dev/null @@ -1,32 +0,0 @@ -# Exercise Session 9, Solutions - -## Question 1 - -```scala -"gcd" -> Name("Not provided (part of the lab)") -``` - -## Question 2 - -```scala -"map" -> Fun("ls", Fun("f", - Match(Name("ls"), - EmptyList, - "x", "xs", - Cons( - Call(Name("f"), Name("x")), - Call(Call(Name("map"), Name("xs")), Name("f")))))) -``` - -```scala -"foldLeft" -> Name("Not provided (part of the lab)") -``` - -## Question 3 - -```scala -"CAS" -> Fun("idx", Fun("old", Fun("new", - IfNonzero(minus(Read(Name("idx")), Name("old")), - Constant(0), - Write(Name("idx"), Name("new"), Constant(1)))))), -``` diff --git a/exercises/solution-11.md b/exercises/solution-11.md deleted file mode 100644 index 60a741b7d52264d421f67586a24c97f47236aff5..0000000000000000000000000000000000000000 --- a/exercises/solution-11.md +++ /dev/null @@ -1,36 +0,0 @@ -# Exercise Session 11, Solutions - -## Question 1 - -### Question 1.1 - -```scala -def succ = (n => f => x => f(n(f)(x))) -``` - -### Question 1.2 - -```scala -def add = (n => m => n(succ)(m)) -``` - -## Question 2 - -### Question 2.1 - -```scala -def size = (l => l(zero)( h => t => succ(size(t)) )) -``` - -### Question 2.2 - - -```scala -def map = (f => l => l(nil)( h => t => cons( f(h) )( map(f)(t) ) )) -``` - -### Question 2.3 - -```scala -def foldRight = (f => z => l => l(z)( h => t => f(h)(foldRight(f)(z)(t)) )) -``` \ No newline at end of file diff --git a/labs/example-lab.md b/labs/example-lab.md deleted file mode 100644 index 60dc0b433c2f80265b2aa14d50a73eddc146a18e..0000000000000000000000000000000000000000 --- a/labs/example-lab.md +++ /dev/null @@ -1,298 +0,0 @@ -# Example lab - -The goal of this lab is to familiarize yourself with the infrastructure and tools used in this class. Even though the grade in this lab won't influence your grade for the course, it is important that you work through this lab carefully. - -## Part 1: Obtaining the Project Files - -First, make sure you've followed the [Tools Setup](tools-setup.md) page. - -**At this point, we strongly encourage you to take the time to read at least the first three chapters of the [Git Book](https://git-scm.com/book/en/v2). If you just copy-paste the commands we give you without understanding them, it's likely that you'll make a mistake somewhere and waste time. Git can be a huge productivity enhancer when used correctly, so it's definitely worth the investment!** - -We'll starting by cloning the repository containing all our lab (make -sure to replace `GASPAR` with your EPFL username (the one with letters, not the -one with number) in the following command). - -```shell -git clone -b example git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-example -``` - -**If this command fails, make sure you've [logged into -gitlab](https://gitlab.epfl.ch/users/sign_in) and [registered in this table](https://docs.google.com/spreadsheets/d/12KvfD_jN5AcApmWhCz7xZmln48fctQOa984RPWrqRkY/edit#gid=0), -then wait a few minutes. -If it still doesn't work it's likely that you didn't correctly upload your ssh -key to gitlab, look at the last part of the [Tools Setup](tools-setup.md) page again.** - -```shell -cd cs210-example -``` - -Now that we've obtained the project, let's take a look at its structure: - -```shell -. -├── build.sbt -├── project -│ ├── ... -└── src - ├── main - │ └── scala - │ └── example - │ └── Lists.scala - └── test - └── scala - └── example - └── ListsSuite.scala -``` - -- All the files ending with `.sbt` or in the `project/` directory are build tool configuration files: you don't need to modify them or look at them for any of the labs -- The project sources are in `src/main/scala/` -- The sources of the unit tests are in `src/test/scala/`. You will need to make all the tests pass to complete the labs, and you should write additional tests to check for cases that our tests do not cover. - -## Part 2: Using sbt - -Start sbt by running: -```shell -sbt -``` - -Once it's finished starting (this may take a while), you'll be able to enter sbt -commands. You can compile your project using `compile` and run the tests with -`test` (this automatically compiles your code if needed to). Note that if -compilation fails, no tests will be run. The first time you'll run `test` in an -lab you should see many errors: that's normal, your job is to make the -tests pass! But first, let's look at a failed test in detail: - - - -This tells us several things: - -- There's a test named `sum of a few numbers (10pts)` in the class `ListsSuite` in the package `example` -- The test failed (that's why it's in red and starts with `==> X`) with an exception: `NotImplementedError`. -- This exception was thrown from the method `???` in `scala.Predef` in the file - `Predef.scala`, this file is not part of our project (that's why it's in - grey), to find the actual error in our code we have to look at where this - method was called from. -- This method was called from method `max` in `example.Lists` in the file - `Lists.scala` at line 40, this is where the bug is! -- It's also important to see where in our test this was called from, here - it's line 102 of `ListsSuite.scala`. - -Time to go fix that bug! The next section will show you how to do that using the IDE. - -## Part 3: Using the IDE - -### Setup - -Let's upgrade the IDE support first, close VSCode if it's open and run: - -```shell -code --force --install-extension scalameta.metals -``` - -### Startup - -To start Code, run the following in the project directory (the same directory where you -previously ran `sbt`), it's important to run Code in the correct directory or -it won't be able to import your project: - -```shell -code . -``` - -(In this command the `.` is important, it's how we tell Code to run in the -current directory) - -(if you see an error `Expected ';'` it means you're inside sbt, open a new -terminal in the same directory) - -The first time the IDE starts, it will take some time to download more -components, eventually it will ask you to import the build, please click "Import -build": - - - -You'll need to wait a bit for the import to finish, if an error appears try -closing and restarting Code in the same way we started it above. -### Usage - -It's now time to dig in! Earlier we talked about a failing test, the stack trace -told us that it was failing on line 102 of the file `ListsSuite.scala`, so let's open that file: - - - -Here's the source code of the test: - - - -The first line gives a name to the test, the second line runs -`sum(List(1, 2, 0))` and tests that it equals 3, but in our case we never got to -this point because an exception was thrown, recall that the second line -of the stack trace was: - -```scala -at example.Lists$.sum(Lists.scala:25) -``` - -This tells us that the crash happened when calling `sum`, we can hover with our mouse over the call to `sum` in the test method to get more information on it: - - - -**If hovering doesn't show this see the [Troubleshooting](#troubleshooting) section.** - -The hover is split into two parts: the first part is: -```scala -def sum(xs: List[Int]): Int -``` -This means that `sum` is a method that takes a `List` of `Int` as argument and -returns an `Int`. The second part is the documentation of `sum`. We can jump to -the definition of sum by `Ctrl+click` (`Cmd+click` on Mac) or by `right click -> -Go to Definition`. Once there we see: - - - -Now we know why the test failed: `sum` calls `???`, which is a method defined in -the Scala standard library that simply crashes your program: whenever you see it -in a lab it means that this is something you need to replace by your own -implementation. - -Once you've implemented this method, you can run `test` from sbt again to see if -the test passed, if you want to run a single test instead of all tests you can -use `testOnly` instead and specify part of the name of the test: -```scala -testOnly -- "--tests=.*max of a few.*" -``` - -You now know enough to be able to work with the IDE, here are some additional tips: - -- When you press `Enter` to make a new line, the IDE will automatically indent the - line if needed (for example, if the last word on the previous line was - `then`), however it will never unindent code for you (for example, when - writing `else`). You can indent code manually by pressing `Tab` and - unindent it by pressing `Backspace` or `Shift + Tab`. -- When working on an lab, you are free to create as many methods, classes and objects as you want. **But you shouldn't change the name of existing methods, classes and objects, because that may break the automated grading system, this is important!**. -- You can see a list of all warnings and errors reported by the compiler by clicking on  at the bottom left of Code. -- The IDE can show you on hover the documentation of classes, defs and vals defined in the current project but support for external project is currently missing. To compensate for this, you can consult the documentation online: - - The documentation for the Scala standard library is at [https://www.scala-lang.org/files/archive/api/2.13.3/](https://www.scala-lang.org/files/archive/api/2.13.3/) - - The documentation for the Java standard library is at [https://docs.oracle.com/en/java/javase/15/docs/api/index.html](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) -- You can customize Code as much as you want, including installing additional extensions, but please avoid installing other Scala-related extensions: they may conflict with the one we use for this course. -- While working on your lab, you will regularly want to go back to the sbt console to run the tests. You could simply run the command `test` every time, but you can take advantage of the watch mode instead: if a command is prefixed by `~`, sbt will watch the source directory for changes and re-run the command every time a file is saved. So a possible workflow is: - - 1. Start the IDE - 2. Start sbt in the terminal (protip: you can start a terminal inside Code from the - menu: `Terminal -> New Terminal`) - 3. Inside sbt, run `~test` - 4. Work in the IDE, and check the output of the sbt console from time to time - -## Part 4: Running your code - -Writing code and running tests is nice, but sometimes more direct feedback is useful, like when you want to experiment with Scala, or try out some methods that you implemented. You can do this using the Scala REPL (Read/Eval/Print Loop) or with a worksheet. - -### The REPL -After having started sbt, you can start the REPL by typing `console`, you will see the following prompt: -```scala -scala> -``` -At this point you can write any Scala expression you want, for example: -```scala -scala> val l = List(3,7,2) -val l: List[Int] = List(3, 7, 2) -``` - -(If you write an expression without wrapping it in a `val` or a `def`, the REPL will give it a name for you, starting with `res`) - -```scala -scala> l.isEmpty -val res0: Boolean = false - -scala> println(res0) -false - -scala> l.tail.head -res1: Int = 7 - -scala> List().isEmpty -res2: Boolean = true -``` - -The classes of the lab are available inside the REPL, so you can for instance import all the methods from `object Lists` and start using `max`: - -```scala -scala> import example.Lists._ -import example.Lists._ - -scala> max(List(1,3,2)) -res1: Int = 3 -``` - -You can enter a multiline expression in the REPL by using `Alt+Enter` instead of `Enter`: - -```scala -scala> if 1 == 1 then - | "a" - | else - | "b" -val res0: String = a -``` - -(on macOS, first go to `Terminal -> Preference -> Profiles -> Keyboard` and then -select `Use Option as Meta key`, then `Option+Enter` will work for multiline -expressions.) - -In order to exit the Scala REPL and go back to sbt, type `Ctrl+D`. - -### The worksheet mode -A *worksheet* is a file where every line of code written in the IDE is executed and its output displayed as a comment. - -#### Creating a worksheet -Any file that ends in `.worksheet.sc` is considered to be a worksheet by the IDE. Once Code is launched in a project, all you have to do is create a new file and save it (`Ctrl+N, Ctrl+S`) using any name as long as it ends in `.worksheet.sc`. - -#### Using the worksheet mode - -Inside this file, you can type any line of code you would type in the REPL. The -worksheet will be automatically run when the code is saved and auto-save is -enabled by default. Each line of code will be executed one by one and its output -will be shown in green on the right. - -## Part 5: Submitting your Solution - -[Click here to learn how to submit your lab.](grading-and-submission.md) - -# Troubleshooting - -## sbt fails to start - -If you see any kind of error when sbt starts that prevents you from using it, -try cleaning the project cache by running: -```shell -git clean -Xdf -``` -Then restarting `sbt`, if this still doesn't work, try deleting the global sbt -cache: -```shell -rm -r ~/.sbt -``` - -## IDE features like type-on-hover or go-to-definition do not work - -It's likely that the build wasn't imported, we can import it manually: - -Click on the "m" logo in the left bar (where the red arrow is in the screenshot below): - - - -In the sidebar that appears, click on "Import build", then wait a bit: - - - -If things still don't work, try restarting Code (launch it in the same way you -started it before, using `code .` from the project directory). If you're still -having issues, try clicking on "Clean compile workspace" from the same -sidebar. - -## Warning about Bloop installed version - -If you get a warning like this: - - - -Please click the first button "Turn off old server". diff --git a/labs/grading-and-submission.md b/labs/grading-and-submission.md deleted file mode 100644 index 0487905c1203502b0f741c3eae7b3bfbfb1d07e8..0000000000000000000000000000000000000000 --- a/labs/grading-and-submission.md +++ /dev/null @@ -1,106 +0,0 @@ -# Grading and submission - -## Local tests and grading - -Each lab is shipped with two sets of tests: - * The tests defined under `src/test/scala`, these are usually incomplete: we - strongly encourage you to write additional tests to exercise every aspect of - your code. You can run these tests from `sbt` using the following command: - ```shell - test - ``` - * The **grading tests**, that we use to grade your labs, these are - provided as a "black box": you can run them but are not allowed to see their - content, to encourage you to write your own tests. You can run them from - `sbt` using the following command: - ```shell - Grading/test - ``` - - Your grade is determined by the number of these tests that pass, see the - next section to see how to actually get a grade. - -(remember that you can always put `~` before an sbt command to automatically -re-run it when you save a file) - -## Committing and pushing your code - -**You need to push your code to gitlab before the deadline for the lab to -receive a grade. If you forget, your grade will be zero.** - -If you've read the first few chapters of [Git -book](https://git-scm.com/book/en/v2) as recommended, you must already be -familiar with committing and pushing, but let's go over the basics once again: - -At any point while working on an lab, you can see what changes you -haven't committed by writing: -```shell -git status -``` - -(If you get the error `Not a valid command: git`, it means you're inside sbt, -you can't run git from sbt itself, you need to open another terminal in the same -directory) - -This will display the list of files you have modified since the last commit, to -see the exact changes you made, run: -```shell -git diff -``` - -To save these changes in a commit, run: (replace `"My message"` by a message -describing the changes since the last commit, see [How to Write a Git Commit -Message](https://chris.beams.io/posts/git-commit/) for some tips on writing -good commit messages) -```shell -git commit -am "My message" -``` - -(It's good practice to commit your code regularly to document your changes) - -You can then synchronize your local git repository with the gitlab server by -first running: -```shell - git pull --no-rebase -``` - -This will merge in your local repository any change we made to the lab -(we only change labs to fix critical bugs found after it's been released, -so most of the time this will not do anything). - -Finally, you can push your changes to gitlab: -```shell -git push -``` - -Note that there are also graphical user interfaces to interact with git, for -example [VSCode has built-in git -support](https://code.visualstudio.com/docs/editor/versioncontrol#_git-support). - -Once you've pushed your code, you can see the result online by going to -`gitlab.epfl.ch/lamp/students-repositories-fall-2021/cs210-GASPAR/pipelines` where -`GASPAR` is your username (you can also access this page from the main page of -your repository by clicking on the rocket icon on the left side of the gitlab -interface, then clicking on "Pipelines"). - - - -The grading pipeline contains two steps: - * *compile*: your code does not compile for grading if the job fail. - * *grade*: the job results in a warning if you do not get the maximum grade - (10.00/10.00) - -If a job is marked "pending", it means there are other students running jobs at -the same time and you'll have to wait a bit for your job to run. - -You can click on the `grade` job to see its output: - - - - - -Your grade is given on the line that starts with `Your overall score for this -lab is` - -**If you push to gitlab multiple times, your final grade will be based on the -last commit you pushed before the deadline.** diff --git a/labs/images/bloop-update.png b/labs/images/bloop-update.png deleted file mode 100644 index 788bc5f8a71c9d1f9f71045a0749562420cc6f41..0000000000000000000000000000000000000000 Binary files a/labs/images/bloop-update.png and /dev/null differ diff --git a/labs/images/clone-url.png b/labs/images/clone-url.png deleted file mode 100644 index 784cec1aecafc709da76a3f23bebadf7cfdc180a..0000000000000000000000000000000000000000 Binary files a/labs/images/clone-url.png and /dev/null differ diff --git a/labs/images/gitlab-public-ssh-key.png b/labs/images/gitlab-public-ssh-key.png deleted file mode 100644 index f57459d9d7862d4a924a327b629583d01725932f..0000000000000000000000000000000000000000 Binary files a/labs/images/gitlab-public-ssh-key.png and /dev/null differ diff --git a/labs/images/gitlab-settings.png b/labs/images/gitlab-settings.png deleted file mode 100644 index 1f5363204a2e91c337bb8296cc8c7efd158d9304..0000000000000000000000000000000000000000 Binary files a/labs/images/gitlab-settings.png and /dev/null differ diff --git a/labs/images/hover.png b/labs/images/hover.png deleted file mode 100644 index 6065791252eb55880f76b370ccc572a3c24c5a1c..0000000000000000000000000000000000000000 Binary files a/labs/images/hover.png and /dev/null differ diff --git a/labs/images/import-build.png b/labs/images/import-build.png deleted file mode 100644 index 509db479f515b1ed4133de36cc0b3da2a65c2985..0000000000000000000000000000000000000000 Binary files a/labs/images/import-build.png and /dev/null differ diff --git a/labs/images/menu-metals.png b/labs/images/menu-metals.png deleted file mode 100644 index 869dfa1f1be431d05fca5d09a97d1ad7e76b85e9..0000000000000000000000000000000000000000 Binary files a/labs/images/menu-metals.png and /dev/null differ diff --git a/labs/images/metals-import.png b/labs/images/metals-import.png deleted file mode 100644 index 57f5c5e4af4139202d440c3fcb59c3d7665aae4a..0000000000000000000000000000000000000000 Binary files a/labs/images/metals-import.png and /dev/null differ diff --git a/labs/images/open-test.png b/labs/images/open-test.png deleted file mode 100644 index b397b1810ff800961b051506ec5f4d5b6de75b5b..0000000000000000000000000000000000000000 Binary files a/labs/images/open-test.png and /dev/null differ diff --git a/labs/images/pipeline-details.png b/labs/images/pipeline-details.png deleted file mode 100644 index 426346c5adbc56e96f48e572c35018fd66456371..0000000000000000000000000000000000000000 Binary files a/labs/images/pipeline-details.png and /dev/null differ diff --git a/labs/images/pipeline-logs.png b/labs/images/pipeline-logs.png deleted file mode 100644 index 607626e390391db912455cd95748cb07459afde2..0000000000000000000000000000000000000000 Binary files a/labs/images/pipeline-logs.png and /dev/null differ diff --git a/labs/images/pipeline-tab.png b/labs/images/pipeline-tab.png deleted file mode 100644 index b2756a91a19ceb5972c00295fb8796958d1a91ae..0000000000000000000000000000000000000000 Binary files a/labs/images/pipeline-tab.png and /dev/null differ diff --git a/labs/images/sbt-test-error.png b/labs/images/sbt-test-error.png deleted file mode 100644 index 3e0856eeee0a8276df224e2d30820f41addd12c1..0000000000000000000000000000000000000000 Binary files a/labs/images/sbt-test-error.png and /dev/null differ diff --git a/labs/images/sum-def.png b/labs/images/sum-def.png deleted file mode 100644 index 43d763dbf432bf203e85b1a9146b74092998a2b5..0000000000000000000000000000000000000000 Binary files a/labs/images/sum-def.png and /dev/null differ diff --git a/labs/images/syntax-error-bug.png b/labs/images/syntax-error-bug.png deleted file mode 100644 index a2a53b294e0b8c848e5a524521268c74436b322d..0000000000000000000000000000000000000000 Binary files a/labs/images/syntax-error-bug.png and /dev/null differ diff --git a/labs/images/test-source.png b/labs/images/test-source.png deleted file mode 100644 index dbd3f7e3a9b2629b196603664a17f07cdbdd2a7f..0000000000000000000000000000000000000000 Binary files a/labs/images/test-source.png and /dev/null differ diff --git a/labs/images/warnings-errors.png b/labs/images/warnings-errors.png deleted file mode 100644 index be5b9d6ff528c1e1b51523217078a54b48f10399..0000000000000000000000000000000000000000 Binary files a/labs/images/warnings-errors.png and /dev/null differ diff --git a/labs/lab-01.md b/labs/lab-01.md deleted file mode 100644 index 31452c142ceb567ad1344a0f1ec9c9c32461a494..0000000000000000000000000000000000000000 --- a/labs/lab-01.md +++ /dev/null @@ -1,126 +0,0 @@ -# Lab 1: Recursion - -**Before starting this lab, please complete the other [first week tasks](https://gitlab.epfl.ch/lamp/cs210#first-week-tasks)!** - -# Setup - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b recfun git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-recfun -cd cs210-recfun -``` - -**If you encounter any issue with the IDE, please refer back to the -[Troubleshooting section of the example lab](example-lab.md#troubleshooting).** - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - -# Be functional! - -This course is about **functional** programming, where you'll learn to program -without using mutation, therefore you're not allowed to use the following -constructs in the labs: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise 1: Pascal's Triangle - -The following pattern of numbers is called _Pascal's triangle_. - - 1 - 1 1 - 1 2 1 - 1 3 3 1 - 1 4 6 4 1 - ... - -The numbers at the edge of the triangle are all `1`, and each number -inside the triangle is the sum of the two numbers above it. Write a -function that computes the elements of Pascal's triangle by means of a -recursive process. - -Do this exercise by implementing the `pascal` function in -`RecFun.scala`, which takes a column `c` and a row `r`, counting from -`0` and returns the number at that spot in the triangle. For example, -`pascal(0,2)=1`, `pascal(1,2)=2` and `pascal(1,3)=3`. - -```scala -def pascal(c: Int, r: Int): Int -``` - -# Exercise 2: Parentheses Balancing - -Write a recursive function which verifies the balancing of parentheses -in a string, which we represent as a `List[Char]` not a `String`. For -example, the function should return `true` for the following strings: - -- (if (zero? x) max (/ 1 x)) -- I told him (that it's not (yet) done). - (But he wasn't listening) - -The function should return `false` for the following strings: -<ul> -<li>:-)</li> -<li>())(</li> -</ul> - -The last example shows that it's not enough to verify that a string -contains the same number of opening and closing parentheses. - -Do this exercise by implementing the `balance` function in -`RecFun.scala`. Its signature is as follows: - -```scala -def balance(chars: List[Char]): Boolean -``` - -There are three methods on `List[Char]` that are useful for this -exercise: - -- `chars.isEmpty: Boolean` returns whether a list is empty -- `chars.head: Char` returns the first element of the list -- `chars.tail: List[Char]` returns the list without the first element - -You can find more information on these methods in the [documentation of List](https://www.scala-lang.org/files/archive/api/2.13.3/scala/collection/immutable/List.html) - -__Hint__: you can define an inner function if you need to pass extra -parameters to your function. - -__Testing__: You can use the `toList` method to convert from a -`String` to a `List[Char]`: e.g. `"(just an) example".toList`. - -# Exercise 3: Counting Change - -Write a recursive function that counts how many different ways you can -make change for an amount, given a list of coin denominations. For -example, there are 3 ways to give change for 4 if you have coins with -denomiation 1 and 2: 1+1+1+1, 1+1+2, 2+2. - -Do this exercise by implementing the `countChange` function in -`RecFun.scala`. This function takes an amount to change, and a list of -unique denominations for the coins. Its signature is as follows: - -```scala -def countChange(money: Int, coins: List[Int]): Int -``` - -Once again, you can make use of functions `isEmpty`, `head` and `tail` -on the list of integers `coins`. - -__Hint__: Think of the degenerate cases. How many ways can you give -change for 0 CHF? How many ways can you give change for >0 CHF, if you -have no coins? - -# Submission - -[When you're done, don't forget to submit your assignment!](grading-and-submission.md) diff --git a/labs/lab-02.md b/labs/lab-02.md deleted file mode 100644 index ecf1800b88a38aa9e7363954e2036f48fda964d0..0000000000000000000000000000000000000000 --- a/labs/lab-02.md +++ /dev/null @@ -1,153 +0,0 @@ -# Lab 2: Purely Functional Sets - -In this assignment, you will work with a functional representation of -sets based on the mathematical notion of characteristic functions. The -goal is to gain practice with higher-order functions. - -## Setup - -Let's upgrade the IDE support first: - -```shell -code --force --install-extension scalameta.metals -``` - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b funsets git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-funsets -cd cs210-funsets -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - -## Representation - -We will work with sets of integers. - -As an example to motivate our representation, how would you represent the set of -all negative integers? You cannot list them all... one way would be to -say: if you give me an integer, I can tell you whether it's in the set -or not: for `3`, I would say `no`; for `-1`, I would say `yes`. - -Mathematically, we call the function which takes an integer as -argument and which returns a boolean indicating whether the given -integer belongs to a set, the _characteristic_ function of the -set. For example, we can characterize the set of negative integers by -the characteristic function `(x: Int) => x < 0`. - -Therefore, we choose to represent a set by its characteristic function -and define a type alias for this representation: - -```scala -type FunSet = Int => Boolean -``` - -Using this representation, we define a function that tests for the -presence of a value in a set: - -```scala -def contains(s: FunSet, elem: Int): Boolean = s(elem) -``` - -## 2.1 Basic Functions on Sets - -Let's start by implementing basic functions on sets. - -1. Define a function which creates a singleton set from one integer - value: the set represents the set of the one given element. Its - signature is as follows: - - ```scala - def singletonSet(elem: Int): FunSet - ``` - - Now that we have a way to create singleton sets, we want to define - a function that allow us to build bigger sets from smaller ones. - -2. Define the functions `union`, `intersect`, and `diff`, which takes - two sets, and return, respectively, their union, intersection and - differences. `diff(s, t)` returns a set which contains all the - elements of the set `s` that are not in the set `t`. These - functions have the following signatures: - - ```scala - def union(s: FunSet, t: FunSet): FunSet - def intersect(s: FunSet, t: FunSet): FunSet - def diff(s: FunSet, t: FunSet): FunSet - ``` - -3. Define the function `filter` which selects only the elements of a - set that are accepted by a given predicate `p`. The filtered - elements are returned as a new set. The signature of `filter` is as - follows: - - ```scala - def filter(s: FunSet, p: Int => Boolean): FunSet - ``` - -## 2.2 Queries and Transformations on Sets - -In this part, we are interested in functions used to make requests on -elements of a set. The first function tests whether a given predicate -is true for all elements of the set. This `forall` function has the -following signature: - -```scala -def forall(s: FunSet, p: Int => Boolean): Boolean -``` - -Note that there is no direct way to find which elements are in a -set. `contains` only allows to know whether a given element is -included. Thus, if we wish to do something to all elements of a set, -then we have to iterate over all integers, testing each time whether -it is included in the set, and if so, to do something with it. Here, -we consider that an integer `x` has the property `-1000 <= x <= 1000` -in order to limit the search space. - -1. Implement `forall` using linear recursion. For this, use a helper - function nested in `forall`. Its structure is as follows (replace - the `???`): - - ```scala - def forall(s: FunSet, p: Int => Boolean): Boolean = - def iter(a: Int): Boolean = - if ??? then - ??? - else if ??? then - ??? - else - iter(???) - iter(???) - ``` - -2. Using `forall`, implement a function `exists` which tests whether a - set contains at least one element for which the given predicate is - true. Note that the functions `forall` and `exists` behave like the - universal and existential quantifiers of first-order logic. - - ```scala - def exists(s: FunSet, p: Int => Boolean): Boolean - ``` - -3. Finally, write a function `map` which transforms a given set into - another one by applying to each of its elements the given - function. `map` has the following signature: - - ```scala - def map(s: FunSet, f: Int => Int): FunSet - ``` - -## Extra Hints - -- Sets are represented as functions. Think about what it _means_ for an element to belong to a set, in terms of function evaluation. For example, how do you represent a set that contains all numbers -between 1 and 100? -- Most of the solutions for this assignment can be written as one-liners. If you have more, you probably need to rethink your solution. In other words, this assignment needs more thinking (whiteboard, pen and paper) than coding ;-). -- If you are having some trouble with terminology, have a look at the [glossary](http://docs.scala-lang.org/glossary/). diff --git a/labs/lab-03.md b/labs/lab-03.md deleted file mode 100644 index 1e9345b12e41e0d13e14dd571f58bf495df8b2ea..0000000000000000000000000000000000000000 --- a/labs/lab-03.md +++ /dev/null @@ -1,134 +0,0 @@ -# Lab 3: Object-Oriented Sets - -In this assignment you will work with an object-oriented -representations based on binary trees. - -## Setup - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b objsets git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-objsets -cd cs210-objsets -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - -## Overview - -For this part, you will earn credit by completing the -`TweetSet.scala` file. This file defines an abstract class `TweetSet` with -two concrete subclasses, `Empty` which represents an empty set, and -`NonEmpty(elem: Tweet, left: TweetSet, right: TweetSet)`, which represents a -non-empty set as a binary tree rooted at `elem`. The tweets are indexed by their text bodies: the bodies of all tweets on the -`left` are lexicographically smaller than `elem` and all bodies of elements on the -`right` are lexicographically greater. - -Note also that these classes are _immutable_: the -set-theoretic operations do not modify `this` but should return a new -set. - -Before tackling this assignment, we suggest you first study the -already implemented methods `contains` and `incl` for inspiration. - -## 1 Filtering - -Implement filtering on tweet sets. Complete the -stubs for the methods `filter` and `filterAcc`. `filter` takes as argument a -function, the predicate, which takes a tweet and returns a -boolean. `filter` then returns the subset of all the tweets in the -original set for which the predicate is true. For example, the -following call: - - tweets.filter(tweet => tweet.retweets > 10) - -applied to a set `tweets` of two tweets, say, where the first tweet was not retweeted -and the second tweet was retweeted 20 times should return a set containing only the -second tweet. - -Hint: start by defining the helper method `filterAcc` which takes an -accumulator set as a second argument. This accumulator contains the -ongoing result of the filtering. - - /** This method takes a predicate and returns a subset of all the elements - * in the original set for which the predicate is true. - */ - def filter(p: Tweet => Boolean): TweetSet - def filterAcc(p: Tweet => Boolean, acc: TweetSet): TweetSet - -The definition of `filter` in terms of `filterAcc` should then be -straightforward. - -## 2 Taking Unions - -Implement union on tweet sets. Complete the stub -for the method `union`. The method `union` takes another set `that`, -and computes a _new_ set which is the union of `this` and `that`, i.e. a set that contains -exactly the elements that are _either_ in `this` _or_ in `that`, _or in both_. - - def union(that: TweetSet): TweetSet - -Note that in this exercise it is your task to find out in which class(es) to -define the `union` method (should it be abstract in class `TweetSet`?). - -**Warning : This method is a crucial part of the assignment. -There are many ways to correctly code it, however some implementations run in an exponential time, so be careful, -an inefficient implementation might result in a timeout during the grading process.** - -## 3 Sorting Tweets by Their Influence - -The more often a tweet is "re-tweeted" (that is, repeated by a different user with or without -additions), the more influential it is. - -The goal of this part of the exercise is to add a method `descendingByRetweet` to `TweetSet` -which should produce a linear sequence of tweets (as an instance of class `TweetList`), ordered by -their number of retweets: - - def descendingByRetweet: TweetList - -This method reflects a common pattern when transforming data structures. While traversing one -data structure (in this case, a `TweetSet`), we're building a second data structure (here, an -instance of class `TweetList`). The idea is to start with the empty list `Nil` (containing no tweets), and to find the tweet with the most retweets in the input `TweetSet`. -This tweet is -removed from the `TweetSet` (that is, we obtain a new `TweetSet` that has all the tweets of the original set except for the tweet that was "removed"; this *immutable* set operation, `remove`, is already implemented for you), and added to the result list by creating a new `Cons`. -After that, the process repeats itself, but now we are searching through a `TweetSet` with one less -tweet. - -Hint: start by implementing the method `mostRetweeted` which returns the most popular tweet of a `TweetSet`. - -## 4 Tying everything together - -In the last step of this assignment your task is to detect influential tweets in -a set of recent tweets. We are providing you with a `TweetSet` containing several -hundred tweets from popular tech news sites in the past few days, located in the -`TweetReader` object (file "TweetReader.scala"). `TweetReader.allTweets` returns -an instance of `TweetSet` containing a set of all available tweets. - -Furthermore, you are given two lists of keywords. The first list corresponds to keywords associated with Google and Android smartphones, while the second list corresponds to keywords associated with Apple and iOS devices. Your objective is to detect which platform has generated more interest or activity in the past few days. - -As a first step, use the functionality you implemented in the first -parts of this assignment to create two different `TweetSet`s, -`googleTweets` and `appleTweets`. The first `TweetSet`, -`googleTweets`, should contain all tweets that mention (in their -"text") one of the keywords in the `google` list. The second -`TweetSet`, `appleTweets`, should contain all tweets that mention one -of the keyword in the `apple` list. Their signature is as follows: - - lazy val googleTweets: TweetSet - lazy val appleTweets: TweetSet - -Hint: use the `exists` method of `List` and `contains` method of class -`java.lang.String`. - -From the _union_ of those two `TweetSet`s, produce `trending`, an -instance of class `TweetList` representing a sequence of tweets ordered -by their number of retweets: - - lazy val trending: TweetList diff --git a/labs/lab-04.md b/labs/lab-04.md deleted file mode 100644 index d26b5547253b9b45fa715aff74fd9b808bab8528..0000000000000000000000000000000000000000 --- a/labs/lab-04.md +++ /dev/null @@ -1,187 +0,0 @@ -# Lab 4: Pattern Matching (Huffman) - -## Setup - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b patmat git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-patmat -cd cs210-patmat -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - - -## Overview - -Huffman coding is a compression algorithm that can be used to -compress lists of characters. - -In a normal, uncompressed text, each character is represented by the same number of bits (usually eight). -In Huffman coding, each character can have a bit representation of a different length, depending on how common a character is: the characters that appear often in a text are represented by a shorter bit sequence than those being used more rarely. -Every huffman code defines the specific bit sequences used to represent each character. - -A Huffman code can be represented by a binary tree whose leaves represent the characters that should be encoded. -The code tree below can represent the characters `A` to `H`. - -The leaf nodes have associated with them a weight which denotes the frequency of appearance of that character. -In the example below, the character `A` has the highest weight 8, while `F` for example has weight 1. - -Every branching node of the code tree can be thought of as a set containing the characters present in the leaves below it. The weight of a branching node is the total weight of the leaves below it: this information is necessary for the construction of the tree. - - - -Note that a given encoding is only optimal if the character frequencies in the encoded text match the weights in the code tree. - -Finally, observe the recursive structure of the coding tree: every sub-tree is itself a valid code tree for a smaller alphabet. - -### Encoding - -For a given Huffman tree, one can obtain the encoded -representation of a character by traversing from the root of the -tree to the leaf containing the character. Along the way, when a -left branch is chosen, a `0` is added to the representation, -and when a right branch is chosen, `1` is added to the representation. -Thus, for the Huffman tree above, the character `D` is encoded as -`1011`. - -### Decoding - -Decoding also starts at the root of the tree. Given a sequence of -bits to decode, we successively read the bits, and for each 0, we -choose the left branch, and for each 1 we choose the right branch. -When we reach a leaf, we decode the corresponding character and then -start again at the root of the tree. As an example, given the -Huffman tree above, the sequence of bits, `10001010` corresponds to -`BAC`. - -## Implementation - -In Scala, a Huffman tree can be represented as follows: - - abstract class CodeTree - case class Fork (left: CodeTree, right: CodeTree, chars: List[Char], weight: Int) extends CodeTree - case class Leaf(char: Char, weight: Int) extends CodeTree - -To begin, implement the following two (hint: very simple) functions using pattern matches on the code tree: - -1. `weight` which returns the total weight of a given Huffman tree. -`def weight(tree: CodeTree): Int = tree match ...` -2. `chars` which returns the list of characters defined in a given Huffman tree. -`def chars(tree: CodeTree): List[Char] = tree match ...` - -Using these functions, it's possible to define `makeCodeTree`, a function -which facilitates the creation of Huffman trees by automatically calculating -the list of characters and the weight when creating a node. -This function is already implemented in the handout template: - - def makeCodeTree(left: CodeTree, right: CodeTree) = - Fork(left, right, chars(left) ::: chars(right), weight(left) + weight(right)) - - -Using `makeCodeTree`, code trees can be constructed manually in the following way: - - val sampleTree = makeCodeTree( - makeCodeTree(Leaf('x', 1), Leaf('e', 1)), - Leaf('t', 2) - ) - -## Constructing Huffman Trees - -Given a text, it's possible to calculate and build an optimal Huffman -tree in the sense that the encoding of that text will be of the minimum -possible length, meanwhile keeping all information (i.e., it is lossless). - -To obtain an optimal tree from a list of characters, you have to define a function `createCodeTree` with the following signature: - - def createCodeTree(chars: List[Char]): CodeTree = ... - -Proceed with the following steps to break up this assignment into smaller parts (the handout template contains more detailed documentation): - -1. Begin by writing a function `times` which calculates the frequency -of each character in the text: -`def times(chars: List[Char]): List[(Char, Int)] = ...` -2. Then, write a function `makeLeafList` which generates a list containing -all the leaves of the Huffman tree to be constructed (the case `Leaf` of -the algebraic datatype `CodeTree`). -The list should be ordered by ascending weights where the -weight of a leaf is the number of times (or the frequency) it appears in -the given text. -`def makeOrderedLeafList(freqs: List[(Char, Int)]): List[Leaf] = ...` -3. Write a simple function `singleton` which checks whether a list of code trees contains only one single tree. -`def singleton(trees: List[CodeTree]): Boolean = ...` -4. Write a function `combine` which (1) removes the two trees with the -lowest weight from the list constructed in the previous step, and (2) -merges them by creating a new node of type `Fork`. Add this new tree -to the list - which is now one element shorter - while preserving the -order (by weight). -`def combine(trees: List[CodeTree]): List[CodeTree] = ...` -5. Write a function `until` which calls the two functions defined above -until this list contains only a single tree. This tree is the optimal -coding tree. The function `until` can be used in the following way: -`until(singleton, combine)(trees)` -where the argument `trees` is of the type `List[CodeTree]`. -6. Finally, use the functions defined above to implement the function -`createCodeTree` which respects the signature shown above. - -## Decoding - -Define the function `decode` which decodes a list of bits (which were -already encoded using a Huffman tree), given the corresponding coding -tree. - - type Bit = Int - def decode(tree: CodeTree, bits: List[Bit]): List[Char] = ... - -Use this function and the `frenchCode` code tree to decode the bit sequence in `secret`. -Store the resulting character sequence in `decodedSecret`. - -## Encoding - -This section deals with the Huffman encoding of a sequence of characters -into a sequence of bits. - -### ...Using a Huffman Tree - -Define the function `encode` which encodes a list of characters using -Huffman coding, given a code tree. - - def encode(tree: CodeTree)(text: List[Char]): List[Bit] = ... - -Your implementation must traverse the coding tree for each character, -a task that should be done using a helper function. - -### ...Using a Coding Table - -The previous function is simple, but very inefficient. You goal is now -to define `quickEncode` which encodes an equivalent representation, but -more efficiently. - - def quickEncode(tree: CodeTree)(text: List[Char]): List[Bit] = ... - -Your implementation will build a coding table once which, for each possible -character, gives the list of bits of its code. The simplest way - but not -the most efficient - is to encode the table of characters as a list of pairs. - - type CodeTable = List[(Char, List[Bit])] - -The encoding must then be done by accessing the table, via a function -`codeBits`. - - def codeBits(table: CodeTable)(char: Char): List[Bit] = ... - -The creation of the table is defined by `convert` which traverses the coding -tree and constructs the character table. - - def convert(t: CodeTree): CodeTable = ... - -Implement the function `convert` by using the function `mergeCodeTables` below: - - def mergeCodeTables(a: CodeTable, b: CodeTable): CodeTable = ... diff --git a/labs/lab-05.md b/labs/lab-05.md deleted file mode 100644 index cd8f959cd957a9952bb2dcdcdad2c79d8fcf72cf..0000000000000000000000000000000000000000 --- a/labs/lab-05.md +++ /dev/null @@ -1,284 +0,0 @@ -# Lab 5: For-comprehensions and Collections - -In this assignment, you will solve the combinatorial problem of finding all -the anagrams of a sentence using the Scala Collections API and for-comprehensions. - -You are encouraged to look at the Scala API documentation while solving this -exercise, which can be found here: - -[http://www.scala-lang.org/api/current/index.html](http://www.scala-lang.org/api/current/index.html) - -Note that Scala uses the `String` from Java, therefore the documentation -for strings has to be looked up in the Javadoc API: - -[http://docs.oracle.com/javase/6/docs/api/java/lang/String.html](http://docs.oracle.com/javase/6/docs/api/java/lang/String.html) - -## Setup - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b forcomp git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-forcomp -cd cs210-forcomp -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - -## The problem - -An anagram of a word is a rearrangement of its letters such that a word with -a different meaning is formed. For example, if we rearrange the letters of -the word `Elvis` we can obtain the word `lives`, which is one of its anagrams. - -In a similar way, an anagram of a sentence is a rearrangement of all the -characters in the sentence such that a new sentence is formed. The new -sentence consists of meaningful words, the number of which may or may not -correspond to the number of words in the original sentence. For example, -the sentence: - - I love you - -is an anagram of the sentence: - - You olive - -In this exercise, we will consider permutations of words anagrams of -the sentence. In the above example: - - You I love - -is considered a separate anagram. - -When producing anagrams, we will ignore character casing and -punctuation characters. - -Your ultimate goal is to implement a method `sentenceAnagrams`, which, -given a list of words representing a sentence, finds all the anagrams -of that sentence. Note that we used the term _meaningful_ in defining -what anagrams are. You will be given a dictionary, i.e. a list of words -indicating words that have a meaning. - -Here is the general idea. We will transform the characters of the sentence -into a list saying how often each character appears. We will call this -list _the occurrence list_. To find anagrams of a word we will find all -the words from the dictionary which have the same occurrence list. -Finding an anagram of a sentence is slightly more difficult. We will -transform the sentence into its occurrence list, then try to extract any -subset of characters from it to see if we can form any meaningful words. -From the remaining characters we will solve the problem recursively and -then combine all the meaningful words we have found with the recursive -solution. - -Let's apply this idea to our example, the sentence `You olive`. Lets -represent this sentence as an occurrence list of characters `eiloouvy`. We start -by subtracting some subset of the characters, say `i`. We are left with -the characters `eloouvy`. - -Looking into the dictionary we see that `i` corresponds to word `I` in -the English language, so we found one meaningful word. We now solve the -problem recursively for the rest of the characters `eloouvy` and obtain -a list of solutions `List(List(love, you), List(you, love))`. We can combine -`I` with that list to obtain sentences `I love you` and `I you love`, -which are both valid anagrams. - -## Representation - -We represent the words of a sentence with the `String` data type: - - type Word = String - -Words contain lowercase and uppercase characters, and no whitespace, -punctuation or other special characters. - -Since we are ignoring the punctuation characters of the sentence -as well as the whitespace characters, we will represent sentences -as lists of words: - - type Sentence = List[Word] - -We mentioned previously that we will transform words and sentences into -occurrence lists. We represent the occurrence lists as sorted lists of -character and integers pairs: - - type Occurrences = List[(Char, Int)] - -The list should be sorted by the characters in an ascending order. -Since we ignore the character casing, all the characters in the occurrence -list have to be lowercase. -The integer in each pair denotes how often the character appears in a -particular word or a sentence. This integer must be positive. Note that -positive also means non-zero -- characters that do not appear in the -sentence do not appear in the occurrence list either. - -Finally, the dictionary of all the meaningful English words is represented -as a `List` of words: - - val dictionary: List[Word] = loadDictionary - -The dictionary already exists for this exercise and is loaded for you using -the `loadDictionary` utility method. - -## Computing Occurrence Lists - -The `groupBy` method takes a function mapping an element of a collection to a -key of some other type, and produces a `Map` of keys and collections of -elements which mapped to the same key. This method _groups_ the elements, -hence its name. - -Here is one example: - - List("Every", "student", "likes", "Scala").groupBy((element: String) => element.length) - -produces: - - Map( - 5 -> List("Every", "likes", "Scala"), - 7 -> List("student") - ) - -Above, the key is the `length` of the string and the type of the key is `Int`. Every -`String` with the same `length` is grouped under the same key -- its `length`. - -Here is another example: - - List(0, 1, 2, 1, 0).groupBy((element: Int) => element) - -produces: - - Map( - 0 -> List(0, 0), - 1 -> List(1, 1), - 2 -> List(2) - ) - -`Map`s provide efficient lookup of all the values mapped to a certain key. Any collection -of pairs can be transformed into a `Map` using the `toMap` method. Similarly, any `Map` can -be transformed into a `List` of pairs using the `toList` method. - -In our case, the collection will be a `Word` (i.e. a `String`) and its elements are -characters, so the `groupBy` method takes a function mapping characters into a desired -key type. - -In the first part of this exercise, we will implement the method `wordOccurrences` -which, given a word, produces its occurrence list. In one of the previous exercises, -we produced the occurrence list by recursively traversing a list of characters. -This time we will use the `groupBy` method from the Collections API (hint: you -may additionally use other methods, such as `map` and `toList`). - - def wordOccurrences(w: Word): Occurrences - -Next, we implement another version of the method for entire sentences. -We can concatenate the words of the sentence into a single word and then reuse -the method `wordOccurrences` that we already have. - - def sentenceOccurrences(s: Sentence): Occurrences - -## Computing Anagrams of a Word - -To compute the anagrams of a word, we use the simple observation that all the anagrams -of a word have the same occurrence list. To allow efficient lookup of all the words -with the same occurrence list, we will have to _group_ the words of the dictionary -according to their occurrence lists. - - lazy val dictionaryByOccurrences: Map[Occurrences, List[Word]] - -We then implement the method `wordAnagrams` which returns the list of anagrams of -a single word: - - def wordAnagrams(word: Word): List[Word] - -## Computing Subsets of a Set - -To compute all the anagrams of a sentence, we will need a helper method which, -given an occurrence list, produces all the subsets of that occurrence list. - - def combinations(occurrences: Occurrences): List[Occurrences] - -The `combinations` method should return all possible ways in which we can pick -a subset of characters from `occurrences`. For example, given the occurrence list: - - List(('a', 2), ('b', 2)) - -the list of all subsets is: - - List( - List(), - List(('a', 1)), - List(('a', 2)), - List(('b', 1)), - List(('a', 1), ('b', 1)), - List(('a', 2), ('b', 1)), - List(('b', 2)), - List(('a', 1), ('b', 2)), - List(('a', 2), ('b', 2)) - ) - -The order in which you return the subsets does not matter as long as they are -all included. Note that there is only one subset of an empty occurrence list, -and that is the empty occurrence list itself. - -Hint: investigate how you can use for-comprehensions to implement parts of this method. - -## Computing Anagrams of a Sentence - -We now implement another helper method called `subtract` which, given two occurrence -lists `x` and `y`, subtracts the frequencies of the occurrence list `y` from the -frequencies of the occurrence list `x`: - - def subtract(x: Occurrences, y: Occurrences): Occurrences - -For example, given two occurrence lists for words `lard` and `r`: - - val x = List(('a', 1), ('d', 1), ('l', 1), ('r', 1)) - val y = List(('r', 1)) - -the `subtract(x, y)` is `List(('a', 1), ('d', 1), ('l', 1))`. - -The precondition for the `subtract` method is that the occurrence list `y` is -a subset of the occurrence list `x` -- if the list `y` has some character then -the frequency of that character in `x` must be greater or equal than the -frequency of that character in `y`. -When implementing `subtract` you can assume that `y` is a subset of `x`. - -Hint: you can use `foldLeft`, and `-`, `apply` and `updated` operations on `Map`. - -Now we can finally implement our `sentenceAnagrams` method for sequences. - - def sentenceAnagrams(sentence: Sentence): List[Sentence] - -Note that the anagram of the empty sentence is the empty sentence itself. - -Hint: First of all, think about the recursive structure of the problem: what -is the base case, and how should the result of a recursive invocation be integrated -in each iteration? Also, using for-comprehensions helps in finding an elegant -implementation for this method. - -Test the `sentenceAnagrams` method on short sentences, no more than 10 characters. -The combinations space gets huge very quickly as your sentence gets longer, -so the program may run for a very long time. However for sentences such as -`Linux rulez`, `I love you` or `Mickey Mouse` the program should end fairly -quickly -- there are not many other ways to say these things. - - -## Further Improvement (Optional) - -This part is optional and is not part of an assignment, nor will be graded. -You may skip this part freely. - -The solution with enlisting all the combinations was concise, but it was not very efficient. -The problem is that we have recomputed some anagrams more than once when recursively -solving the problem. -Think about a concrete example and a situation where you compute the anagrams of the same -subset of an occurrence list multiple times. - -One way to improve the performance is to save the results obtained the first time -when you compute the anagrams for an occurence list, and use the stored result if -you need the same result a second time. -Try to write a new method `sentenceAnagramsMemo` which does this. diff --git a/labs/lab-06.md b/labs/lab-06.md deleted file mode 100644 index a90df3fbd21ce6cb633d3132c035b78b4b426bba..0000000000000000000000000000000000000000 --- a/labs/lab-06.md +++ /dev/null @@ -1,159 +0,0 @@ -# Lab 6: QuickCheck - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b quickcheck git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-quickcheck -cd cs210-quickcheck -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - -## QuickCheck - -In this assignment, you will work with the -[ScalaCheck](https://github.com/rickynils/scalacheck/blob/master/doc/UserGuide.md) -library for automated specification-based testing. - -You're given several implementations of a purely functional data -structure: a heap, which is a priority queue supporting operations `insert`, `meld`, -`findMin`, `deleteMin`. Here is the interface: - - trait Heap { - type H // type of a heap - type A // type of an element - def ord: Ordering[A] // ordering on elements - - def empty: H // the empty heap - def isEmpty(h: H): Boolean // whether the given heap h is empty - - def insert(x: A, h: H): H // the heap resulting from inserting x into h - def meld(h1: H, h2: H): H // the heap resulting from merging h1 and h2 - - def findMin(h: H): A // a minimum of the heap h - def deleteMin(h: H): H // a heap resulting from deleting a minimum of h - } - -All these operations are _pure_; they never modify the given heaps, -and may return new heaps. This purely functional interface is taken -from Brodal & Okasaki's paper, [_Optimal Purely Functional Priority Queues_](http://www.brics.dk/RS/96/37/BRICS-RS-96-37.pdf). - -A priority queue is a queue, in which each element is assigned a "priority". In -classical queues, elements can be retrieved in first-in, first-out order, whereas -in a priority queue, elements are retrieved as per the priority they are assigned. -As such, classical queues are therefore just priority queues where the priority is -the order in which elements are inserted. - -As seen in the above interface, we can create a queue by - - * instantiating an `empty` queue. - * `insert`ing an element into a queue (with an attached priority), thereby creating - a new queue. - * `meld`ing two queues, which results in a new queue that contains all the elements of the - first queue and all the elements of the second queue. - -In addition, we can can test whether a queue is empty or not with `isEmpty`. If -you have a non-empty queue, you can find its minimum with `findMin`. You can also -get a smaller queue from a non-empty queue by deleting the minimum element with -`deleteMin`. In this assignment, the heap operates on `Int` elements with their -values as priorities, so `findMin` finds the least integer in the heap. - -You are given multiple implementations of `IntHeaps` in file -`src/main/scala/quickcheck/Heap.scala`. Only one of these is correct, while -the other ones have bugs. Your goal is to write some properties that will -be automatically checked. All the properties you write should be -satisfiable by the correct implementation, while at least one of them -should fail in each incorrect implementation, thus revealing it's buggy. - -You should write your properties in the body of the `QuickCheckHeap` -class in the file `src/main/scala/quickcheck/QuickCheck.scala`. - -## Part 1: A Heap Generator - -Before checking properties, we must first generate some heaps. Your first task is -to implement such a generator: - - lazy val genHeap: Gen[H] = ??? - -For doing this, you can take inspiration from the lecture on generators and monads. -Here are some basic generators that you can combine together to create larger ones: - - * `arbitrary[T]` is a generator that generates an arbitrary value of type `T`. As we are interested in `IntHeaps` it will generate arbitrary integer values, uniformly at random. - * `oneOf(gen1, gen2)` is a generator that picks one of `gen1` or `gen2`, uniformly - at random. - * `const(v)` is a generator that will always return the value `v`. - -You can find many more useful ones either in the ScalaCheck [user guide](https://github.com/rickynils/scalacheck/blob/master/doc/UserGuide.md) or in -the [Scaladocs](https://javadoc.io/doc/org.scalacheck/scalacheck_2.13/1.14.2/org/scalacheck/Gen$.html). - -For instance, we can write a generator for maps of type `Map[Int, Int]` as follows: - - lazy val genMap: Gen[Map[Int,Int]] = oneOf( - const(Map.empty[Int,Int]), - for - k <- arbitrary[Int] - v <- arbitrary[Int] - m <- oneOf(const(Map.empty[Int,Int]), genMap) - yield - m.updated(k, v) - ) - -## Part 2: Writing properties - -Now that you have a generator, you can write property-based tests. The idea behind -property-based testing is to verify that certain properties hold on your -implementations. Instead of specifying exactly which inputs our properties should -satisfy, we instead generate random inputs, and run each property test on these -randomly generated inputs. This way we increase the likelihood that our implementation -is correct. - -For example, we would like to check that adding a single element to an empty heap, -and then removing this element, should yield the element in question. We would -write this requirement as follows: - - property("min1") = forAll { (a: Int) => - val h = insert(a, empty) - findMin(h) == a - } - -Another property we might be interested in is that, for any heap, adding the minimal -element, and then finding it, should return the element in question: - - property("gen1") = forAll { (h: H) => - val m = if isEmpty(h) then 0 else findMin(h) - findMin(insert(m, h)) == m - } - -In `src/main/scala/quickcheck/QuickCheck.scala`, write some more properties that -should be satisfied. Your properties should at least cover the following relevant facts: - - * If you insert any two elements into an empty heap, finding the - minimum of the resulting heap should get the smallest of the two - elements back. - - * If you insert an element into an empty heap, then delete the - minimum, the resulting heap should be empty. - - * Given any heap, you should get a sorted sequence of elements when - continually finding and deleting minima. (Hint: recursion and helper - functions are your friends.) - - * Finding a minimum of the melding of any two heaps should return a - minimum of one or the other. - - -In order to get full credit, all tests should pass, that is you should -correctly identify each buggy implementation while only writing -properties that are true of heaps. Your properties should cover all of the above-stated relevant facts. -You are free to write as many or as few properties as you want in order to achieve a full passing suite. - -Note that this assignment asks you to write tests whose content captures all of the above relevant facts, -and whose execution correctly differentiates correct from incorrect heaps among the heaps given to you. -You need not worry about additional buggy heaps that someone else might write. diff --git a/labs/lab-07.md b/labs/lab-07.md deleted file mode 100644 index d3544aeaa21b752663e16b6c652725e5971119c2..0000000000000000000000000000000000000000 --- a/labs/lab-07.md +++ /dev/null @@ -1,208 +0,0 @@ -# Lab 7: Bloxorz (Streams) - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b streams git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-streams -cd cs210-streams -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - -## QuickCheck - -In this assignment you will implement a solver for a simplified version of a Flash game -named "Bloxorz" using lazy evaluation. - -As in the previous assignments, you are encouraged to look at the Scala API documentation while solving this exercise, which can be found here: - -[http://www.scala-lang.org/api/current/index.html](http://www.scala-lang.org/api/current/index.html) - -## Bloxorz - -Bloxorz is a game in Flash, which you can access [here](https://www.coolmathgames.com/0-bloxorz). As a first step for this assignment, *play it* for a few levels. - -The objective of Bloxorz is simple; you must navigate your rectangular block to the hole at the end of the board, by rolling it, in the fewest number of moves possible. A block can be moved in 4 possible directions, left, right, up, down, using the appropriate keys on the keyboard. - -You will quickly notice that for many levels, you are, in your head, trying to walk through different configurations/positions of where the block can be in order to reach it to the goal position. Equipped with some new programming skills, you can now let your computer do the work! - -The idea of this assignment is to code a solver for a simplified version of this game, with no orange tiles, circles or crosses on the terrain. The goal of your program, given a terrain configuration with a start position and a goal position, is to return the _exact_ sequence of keys to type in order to reach the goal position. Naturally, we will be interested in getting the _shortest_ path as well. - -### State-space Exploration - -The theory behind coding a solver for this game is in fact be applicable to many different problems. The general problem we are trying to solve is the following: - * We start at some initial state `S`, and we are trying to reach an end state `T`. - * From every state, there are possible transitions to other states, some of which are out of bounds. - * We explore the states, starting from `S`. by exploring its neighbors and following the chain, until we reach `T`. There are different ways of exploring the state space. On the two ends of the spectrum are the following techniques: - * **depth-first search**: when we see a new state, we immediately explore its direct neighbors, and we do this all the way down, until we reach a roadblock. Then we backtrack until the first non-explored neighbor, and continue in the same vein. - * **breadth-first search**: here, we proceed more cautiously. When we find the neighbors of our current state, we explore each of them for each step. The respective neighbors of these states are then stored to be explored at a later time. - -## Game Setup - -Let us start by setting up our platform. The trait `GameDef` will contain all the logic regarding how the terrain is setup, the blocks are represented and how they move. - -### Positions - -A position on the game board is represented using the `case class Pos(x:Int, y:Int)`, where `x` and `y` represent its coordinates. The scaladoc comment on class `Pos` explains how to interpret the coordinates: - -- The `x` coordinate denotes the position on the vertical axis -- The `y` coordinate is used for the horizontal axis -- The coordinates increase when moving down and right - -Illustration: - - 0 1 2 3 <- y axis - 0 o o o o - 1 o o o o - 2 o # o o # is at position Pos(2, 1) - 3 o o o o - - ^ - | - - x axis - - -### The Terrain - -We represent our terrain as a function from positions to booleans: - - type Terrain = Pos => Boolean - -The function returns `true` for every position that is inside the terrain. Terrains can be created easily from a string representation using the methods in the file `StringParserTerrain.scala`. - -Your first task is to implement two methods in trait `StringParserTerrain` that are used to parse the terrain and the start / end positions. The Scaladoc comments give precie instructions how they should be implemented. - - def terrainFunction(levelVector: Vector[Vector[Char]]): Pos => Boolean = ??? - def findChar(c: Char, levelVector: Vector[Vector[Char]]): Pos = ??? - - - - -### Blocks - -Back in the file `GameDef.scala`, a block is a 2 x 1 x 1 cuboid. We represent it as a case class which contains two fields, the 2d position of both the cubes which make up the block. - -A `Block` is therefore a `case class Block(b1: Pos, b2: Pos)`, and can move in four different directions, each time yielding a new block. To this effect, the methods `left`, `right`, `up` and `down` are provided. - -Given this, you can now define a method `isStanding` which tells us whether the Block is standing or not: - - def isStanding: Boolean = ??? - - -Next, implement a method `isLegal` on Block which tells us whether a block is on the terrain or off it: - - def isLegal: Boolean = ??? - -Finally, we need to implement a method that constructs the initial block for our simulation, the block located at the start position: - - def startBlock: Block = ??? - - -### Moves and Neighbors - -To record which moves we make when navigating the block, we represent the four possible moves as case objects: - - sealed abstract class Move - case object Left extends Move - case object Right extends Move - case object Up extends Move - case object Down extends Move - -You can now implement the functions `neighbors` and `legalNeighbors` on `Block`, which return a list of tuples: the neighboring blocks, as well as the move to get there. - - def neighbors: List[(Block,Move)] = ??? - def legalNeighbors: List[(Block,Move)] = ??? - - -## Solving the Game - -Now that everything is set up, we can concentrate on actually coding our solver which is defined in the file `Solver.scala`. - -We could represent a path to a solution as a `LazyList[Block]`. We however also need to make sure we keep the history on our way to the solution. Therefore, a path is represented as a `LazyList[(Block, List[Move])]`, where the second part of the pair records the history of moves so far. Unless otherwise noted, the last move is the `head` element of the `List[Move]`. - -First, implement a function `done` which determines when we have reached the goal: - - def done(b: Block): Boolean = ??? - -#### Finding Neighbors - -Then, implement a function `neighborsWithHistory`, which, given a block, and its history, returns a lazy list of neighboring blocks with the corresponding moves. - - def neighborsWithHistory(b: Block, history: List[Move]): LazyList[(Block, List[Move])] = ??? - -As mentioned above, the history is ordered so that the most recent move is the head of the list. If you consider Level 1 as defined in `Bloxorz.scala`, then - - neighborsWithHistory(Block(Pos(1,1),Pos(1,1)), List(Left,Up)) - -results in a lazy list with the following elements (given as a set): - - Set( - (Block(Pos(1,2),Pos(1,3)), List(Right,Left,Up)), - (Block(Pos(2,1),Pos(3,1)), List(Down,Left,Up)) - ) - -You should implement the above example as a test case in the test suite `BloxorzSuite`. - -Hint: You can convert a `List`, a `Set` or any other collection into a -`LazyList` by calling `.to(LazyList)` on it. - -#### Avoiding Circles - -While exploring a path, we will also track all the blocks we have seen so far, so as to not get lost in circles of movements (such as sequences of left-right-left-right). Implement a function `newNeighborsOnly` to this effect: - - def newNeighborsOnly(neighbors: LazyList[(Block, List[Move])], - explored: Set[Block]): LazyList[(Block, List[Move])] = ??? - -Example usage: - - newNeighborsOnly( - Set( - (Block(Pos(1,2),Pos(1,3)), List(Right,Left,Up)), - (Block(Pos(2,1),Pos(3,1)), List(Down,Left,Up)) - ).to(LazyList), - - Set(Block(Pos(1,2),Pos(1,3)), Block(Pos(1,1),Pos(1,1))) - ) - -returns - - Set( - (Block(Pos(2,1),Pos(3,1)), List(Down,Left,Up)) - ).to(LazyList) - -Again, you should convert this example into a test case. - -#### Finding Solutions - -Now to the crux of the solver. Implement a function `from`, which, given an initial lazy list and a set of explored blocks, creates a lazy list containing the possible paths starting from the head of the initial lazy list: - - def from(initial: LazyList[(Block, List[Move])], - explored: Set[Block]): LazyList[(Block, List[Move])] = ??? - -Note: pay attention to how the path is constructed: as discussed in the introduction, the key to getting the shortest path for the problem is to explore the space in a breadth-first manner. - -Hint: The case study lecture about the water pouring problem (7.5) might help you. - -#### Putting Things together - -Finally we can define a `lazy val pathsFromStart` which is a lazy list of all the paths that begin at the starting block: - - lazy val pathsFromStart: LazyList[(Block, List[Move])] = ??? - -We can also define `pathToGoal` which is a lazy list of all possible pairs of goal blocks along with their history. Indeed, there can be more than one road to Rome! - - lazy val pathsToGoal: LazyList[(Block, List[Move])] = ??? - -To finish it off, we define `solution` to contain the (or one of the) shortest list(s) of moves that lead(s) to the goal. - -**Note: the `head` element of the returned `List[Move]` should represent the first move that the player should perform from the starting position.** - - lazy val solution: List[Move] = ??? diff --git a/labs/lab-08.md b/labs/lab-08.md deleted file mode 100644 index 3c736ddb624c7f880b1e9fd2e59e3613653db161..0000000000000000000000000000000000000000 --- a/labs/lab-08.md +++ /dev/null @@ -1,283 +0,0 @@ -# Lab 8: Type-Directed Programming (Codecs) - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b codecs git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-codecs -cd cs210-codecs -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - -## Overview - -The goal of this assignment is to implement a small serialization library. This library -will be able to encode Scala values (such as instances of case classes) into [JSON] documents -that can be sent over the wire (or saved to a file). Conversely, the library will be able -to decode JSON documents as Scala values. JSON serialization is often used by web servers. - -Please make sure you are familiar with the [JSON] serialization format before starting -the assignment. - -The library will follow a "type-directed" approach. This means that it will use a type-class -`Encoder[A]` to model the ability of encoding a value of type `A` into JSON, and a type-class -`Decoder[A]` to model the ability of decoding a JSON document as a value of type `A`. - -First, you will define given instances for simple types (e.g., `Int`, `String`, etc.). -Then, you will define conditional instances to combine encoders and decoders together to -handle more complex types. - -To make things easier, -the encoders and decoders implemented in this assignment don’t directly work with -JSON blobs, but they work with an intermediate `Json` data type: - -~~~ -enum Json: - /** The JSON `null` value */ - case Null - /** JSON boolean values */ - case Bool(value: Boolean) - /** JSON numeric values */ - case Num(value: BigDecimal) - /** JSON string values */ - case Str(value: String) - /** JSON objects */ - case Obj(fields: Map[String, Json]) - /** JSON arrays */ - case Arr(items: List[Json]) -~~~ - -Here is an example of a JSON value: - -~~~ -{ - "foo": 0, - "bar": [true, false] -} -~~~ - -It can be represented as follows with the `Json` data type: - -~~~ -Json.Obj(Map( - "foo" -> Json.Num(0), - "bar" -> Json.Arr(Json.Bool(true), Json.Bool(false)) -)) -~~~ - -With this `Json` type being defined, **encoding** a value of type `A` consists -of transforming it into a value of type `Json`: - -~~~ -trait Encoder[-A]: - /** Encodes a value of type `A` into JSON */ - def encode(value: A): Json -~~~ - -Unlike arbitrary JSON values, JSON objects have the special property that -two objects can be combined to build a bigger JSON object containing both -objects’ fields. We use this combining property of JSON objects to define -the `zip` method on `Encoder` returning JSON objects. We do so in a -subclass of `Encoder` called `ObjectEncoder`: - -~~~ -trait ObjectEncoder[-A] extends Encoder[A]: - // Refines the encoding result to `Json.Obj` - def encode(value: A): Json.Obj - - def zip[B](that: ObjectEncoder[B]): ObjectEncoder[(A, B)] = ... -~~~ - -Conversely, **decoding** a value of type `A` consists in transforming -a value of type `Json` into a value of type `A`: - -~~~ -trait Decoder[+A]: - /** - * @param data The data to de-serialize - * @return The decoded value wrapped in `Some`, or `None` if decoding failed - */ - def decode(data: Json): Option[A] -~~~ - -Note that the decoding operation returns an `Option[A]` instead of just -an `A` because the decoding process can fail (`None` means that it was -impossible to produce an `A` from the supplied JSON data). - -Given instances of encoders and decoders are defined in the `EncoderInstances` -and `DecoderInstances` traits, respectively. These traits are inherited by the `Encoder` -and `Decoder` companion objects, respectively. By doing so, we make the given -instances automatically available, removing the need for explicitly importing them. - -We provide you with a `parseJson` function that parses a JSON blob from a `String` into -a `Json` value, and a `renderJson` function that turns a `Json` value into a JSON -blob in a `String`. You can use them to experiment with the encoders and decoders that -you write. The functions `parseJson` and `renderJson` are defined in the file -`Util.scala`. - -## Your Task - -Your work consists in writing codec instances that can be combined together to build -codec instances for more complex types. You will start by writing instances for basic -types (such as `String` or `Boolean`) and you will end up writing instances for -case classes. - -Open the file `Codecs.scala`. It contains the definition of the types `Json`, -`Encoder`, `ObjectEncoder` and `Decoder`. Complete the partially implemented given instance -definitions (replace the `???` with proper implementations) and introduce new given instance -definitions as needed (look for `TODO` comments). - -At any time, you can follow your progress by running the `test` sbt task. You can -also use the `run` sbt task to run the `Main` program defined at the bottom of -the `codecs.json` file. Last, you can create a REPL session with the `console` sbt -task, and then experiment with your code: - -~~~ -sbt:progfun2-codecs> console - -scala> import codecs._ -import codecs._ - -scala> Util.parseJson(""" { "name": "Bob", "age": 10 } """) -val res0: Option[codecs.Json] = Some(Obj(Map(name -> Str(Bob), age -> Num(10)))) - -scala> res0.flatMap(_.decodeAs[Person]) // This will crash until you implement it in this assignment -val res1: Option[codecs.Person] = Some(Person(Bob,10)) - -scala> summon[Encoder[Int]] -val res2: codecs.Encoder[Int] = codecs.Encoder$$anon$1@74d8fde0 - -scala> res2.encode(42) -val res3: codecs.Json = Num(42) - -scala> :quit -~~~ - -Remember that if you make any change to the code, you'll need to quit the console -and start it again to run the updated code. Alternatively and as usual you can -also use a worksheet. - -### Basic Codecs - -Start by implementing the given instances of `Encoder[String]` and `Encoder[Boolean]`, -and the corresponding given instances of `Decoder[Int]`, `Decoder[String]` and `Decoder[Boolean]`. - -Make sure that your `Int` decoder rejects JSON floating point numbers. - -#### Troubleshooting - -#### Error when compiling -If `compile` fails with a long error message containing: -```scala -[error] scala.MatchError: ClassInfo(... -``` -It means you're running on Java >= 14. We only support Java 8 in this -course, refer back to [Step 2 of the Tools -Setup page](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/tools-setup.md) -which gives instructions for installing Java 8 using `cs`. - -#### Error when running the grading tests - -The grading tests (run with `grading:test` or on gitlab) will not work -at all until this part of the assignment is complete, if you get an error like -this: -```scala -==> X codecs.CodecsSuite.initializationError 0.002s java.lang.NoClassDefFoundError: Lcodecs/EncoderInstances$given_Encoder_Boolean$; -``` -It means you haven't defined one of the given instance mentioned above (make -sure you define them as anonymous instance, so `given Encoder[Boolean]`, not -`given booleanEncoder as Encoder[Boolean]`, this is required for our grading -tests to work). - -### Derived Codecs - -The next step consists in implementing a codec for lists of elements of type `A`, given -a codec for type `A`. The encoder instance for lists is already implemented. Fill in -the definition of the corresponding decoder. - -Once you have defined the encoder and decoder for lists, you should be able to -**summon** them for any list containing elements that can be encoded and decoded. -You can try, for instance, to evaluate the following expressions in the REPL: - -~~~ -summon[Encoder[List[Int]]] -summon[Decoder[List[Boolean]]] -~~~ - -### JSON Object Codecs - -Next, implement codecs for JSON objects. The approach consists in defining codecs -for JSON objects having a single field, and then combining such codecs to handle -JSON objects with multiple fields. - -For example, consider the following JSON object with one field `x`: - -~~~ -{ - "x": 1 -} -~~~ - -An encoder for this JSON object can be defined by using the provided -`ObjectEncoder.field` operation, which takes the field name as a parameter and -an implicit `Encoder` for the field value: - -~~~ -val xField = ObjectEncoder.field[Int]("x") -~~~ - -Here is an example of use of the `xField` encoder: - -~~~ -scala> xField.encode(42) -val res0: codecs.Json.Obj = Obj(Map(x -> Num(42))) -~~~ - -Last, to define an encoder producing a JSON object with more than one field, you can -combine two `ObjectEncoder` instances with the `zip` operation. This operation -returns an `ObjectEncoder` producing a JSON object with the fields of the two -combined encoders. For instance, you can define an encoder producing an object -with two fields `x` and `y` as follows: - -~~~ -val pointEncoder: ObjectEncoder[(Int, Int)] = - val xField = ObjectEncoder.field[Int]("x") - val yField = ObjectEncoder.field[Int]("y") - xField.zip(yField) -~~~ - -Implement a `Decoder.field` operation corresponding to the `ObjectEncoder.field` -operation. - -### Codecs for Case Classes - -The `zip` operation mentioned in the previous section only returns codecs for tuples. -It would be more convenient to work with high-level data types (for instance, a -`Point` data type, rather than a pair of coordinates). - -Both encoders and decoders have a `transform` operation that can be used to transform -the type `Json` values are encoded from, or decoded to, respectively. You can -see in the assignment how it is used to define a given `Encoder[Person]`. - -Define a corresponding `Decoder[Person]`, and then define a given instance of `Encoder[Contacts]` -and a given instance of `Decoder[Contacts]`. - -## Bonus Questions - -- Can you **explicitly** write the value inferred by the compiler when it summons - the `Encoder[List[Person]]`? -- Would it be possible to define codecs for optional fields? -- Would it be possible to define a function that provides a given instance of - `Encoder[Option[A]]` for any type `A` for which there is a given instance of `Encoder[A]` - (like we do with `Encoder[List[A]]`)? -- Would it be possible to define codecs for sealed traits in addition to case - classes? - -[JSON]:https://www.json.org diff --git a/labs/lab-09.md b/labs/lab-09.md deleted file mode 100644 index 8f29bed3993bfc8641ae81888b439d0ad8e3dc79..0000000000000000000000000000000000000000 --- a/labs/lab-09.md +++ /dev/null @@ -1,144 +0,0 @@ -# Lab 9: Recursive Language (interpreter) - -You can use the following commands to make a fresh clone of your repository: - -```shell -git clone -b interpreter git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-interpreter -cd cs210-interpreter -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - **Make sure to submit your assignment before the deadline written in [README.md](/README.md)** - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - - -## Overview - -The goal of this final assignment is to extend the simple programming language presented in the lecture with a list-like datatype. Recall the datatype of expressions: - -~~~scala -enum Expr: - case Constant(value: Int) - case Name(name: String) - case BinOp(op: BinOps, arg1: Expr, arg2: Expr) - case IfNonzero(cond: Expr, caseTrue: Expr, caseFalse: Expr) - case Call(function: Expr, arg: Expr) - case Fun(param: String, body: Expr) -~~~ - -We extend this datatype with 3 extra cases: - -~~~scala -enum Expr: - [...] - case Empty - case Cons(head: Expr, tail: Expr) - case Match(scrutinee: Expr, caseEmpty: Expr, - headName: String, tailName: String, caseCons: Expr) -~~~ - -`Empty` corresponds to the empty list, also known as `Nil` in Scala. `Cons` *cons*-tructs memory objects holding two values, called head and tail. It is our language analog to Scala's `::`. Finally, `Match` is a pattern matching expression over lists. It takes 5 arguments: - -- `scrutinee`, the expression that's being matched over -- `caseEmpty `, the result of the pattern matching when `scrutinee` evaluates to `Empty` -- `caseCons`, the result of the pattern matching when `scrutinee` evaluates to `Cons` -- `headName` and `tailName` are names that *bind* the two values of `Cons` in `caseCons`. - -`Match` can be also explained by analogy to Scala's pattern matching. The 5 arguments described above correspond to the placeholders in the following expression: - -~~~scala -$scrutinee match - case Nil => $caseEmpty - case $headName :: $tailName => $caseCons -~~~ - -## Running the interpreter - -You can use (and update!) the `main` method at the end of the `RecursiveLanguage` object to execute programs using the interpreter (call `run` from sbt to run the program). To execute programs, use eval (or tracingEval, the debugging with logging enabled). These functions takes two arguments, the expression that's being interpreted, and a set of top-level definitions given to the interpreter. - -## Examples functions - -Once you completed the recitation session, transcribe your implementations of `gcd`, `map` and `foldLeft` into the lab. These definitions should go into `val definitions` at the end of `RecursiveLanguage.scala`. You can see your `gcd` implementation in action by changing the body of the `main` method to: - -~~~scala -def main(args: Array[String]): Unit = - tracingEval(Call(Call(N("gcd"), C(6)), C(9)), definitions) -~~~ - -Execute the interpreter using `run` from sbt. With the reference implementation, the trace looks as follows: - -~~~ -gcd(6)(9) -| gcd(6) -| FUN: (a => (b => (if b then gcd(b)((% a b)) else a))) ARG: 6 -| (b => (if b then gcd(b)((% 6 b)) else 6)) -| +--> (b => (if b then gcd(b)((% 6 b)) else 6)) -[...] -+--> 3 - ~~> Constant(3) -~~~ - -A correct implementation of `gcd` should already give you a passing test (it doesn't use any list constructs!). Can will be able to play around with your `map` and `foldLeft` implementations once you complete the assignment. - -Update the `show` function to support pretty-printing of lists. We suggest (but do not test) that you mirror the Scala syntax for list constructors (`1 :: 2 :: 3 :: Nil`) and for pattern matching. - -Also implement `foldRight`. In the reference solution, it pretty prints as follows: - -~~~scala -def foldRight = - (ls => (z => (fold => ls match { case nil => z; case x :: xs => fold(x)(foldRight(xs)(z)(fold)) }))) -~~~ - -You might have noticed while compiling the project the presence of several warnings about pattern matching exhaustivity. These warnings appeared when we extended `enum Expr`, and should be all gone once you completed your implementation. - -## Evaluation - -Update the `eval` function to support `Empty`, `Cons` and `Match`. `Empty` should evaluate to itself. Likewise, `Cons` should evaluate to a `Cons` with evaluated arguments. `Match` should first evaluate its `scrutinee`, then either reduce to `caseEmpty`, reduce to `caseCons` or raise an error if the `scrutinee` is not a list. - -Adding cases in the `eval` function should be sufficient to evaluate `Match` expressions in isolation (see `evalTests` in `RecursiveLanguageSuite.scala`), but extra work is needed to support `Match` used into functions and nested `Match`-s. - -### Substitution - -Substitution is implemented using 3 functions, `subst`, `freeVars` and `alphaConvert`. That complexity is need to solve the variable capture problem, which we will explain in this section using an example. Suppose the following definitions for factorial and twice (in Scala): - -~~~scala -val fact: - Int => Int = - n => if n == 0 then 1 else n * fact(n - 1) - -val twice: - (Int => Int) => Int => Int = - f => fact => f(f(fact)) -~~~ - -Note the name conflict between the second argument of `twice` and the fact function. Let's evaluate `twice(fact)(3)` using naive substitution: - -~~~scala -twice(fact)(3) ---> twice(n => if n == 0 then 1 else n * fact(n - 1))(3) ---> fact => f(f(fact)) [substitute f by n => if n == 0 then 1 else n * fact(n - 1)] ---> *BOOM* -~~~ - -The naive substitution would break with the example above because of the recursion in factorial. A simple syntactic replacement of `f` would *change* the meaning of `fact` from a reference to the `fact` function (the recursive call) to a reference to the second argument of twice. - -To solve this problem, substitution needs to carefully avoid such accidental capture. To detect name clashes, we first compute the set of names "at-risk", which we call *free variables*. When substituting `f` by `n => if n == 0 then 1 else n * fact(n - 1)` the name at risk is `fact`. The variable `fact` is called a *free variable* in that example because it doesn't have local meaning, it's "free" when we consider that expression in isolation. - -Whenever we detect a name clash, we can work around it by renaming the problematic variable. This operation is traditionally called alpha conversion. The correct version of substitution would evaluate `twice(fact)(3)` as follows: - -~~~scala -twice(fact)(3) ---> twice(n => if n == 0 then 1 else n * fact(n - 1))(3) ---> (fact => f(f(fact)))(3) [rename fact to fact', then substitute f by n => if n == 0 then 1 else n * fact(n - 1)] ---> (fact' => f(f(fact')))(3) [substitute f by n => if n == 0 then 1 else n * fact(n - 1)] ---> [...] ---> 720 -~~~ - -Looking back at pattern matching expression, we can see that the two binders of a `Match` suffer from the same variable capturing problem than function. Indeed, given an expression of shape `(h :: t) match { case x :: xs => body }`, when we substitute `x` by `h` and `xs` by `t` in `body`, we need to avoid changing the meaning of free variables in `h` and `t`. - -Update `freeVars` and `alphaConvert` to with cases for `Empty`, `Cons` and `Match`. Have a look at the corresponding unit tests, `freeVarsTests` and `alphaConvertTests` in `RecursiveLanguageSuite.scala`. Finally, update `subst` with capture avoiding substitution for pattern matching. Note that `subst` is only tested using integration tests, so make sure that you have all other tests passing before starting to implement that last function. Also note that this assignment doesn't have any black-box tests (no need to run `grading:test`, `test` will run all the tests). diff --git a/labs/tools-setup.md b/labs/tools-setup.md deleted file mode 100644 index f516742ab62d6cfd7cc6d41df9dd9743965a77f0..0000000000000000000000000000000000000000 --- a/labs/tools-setup.md +++ /dev/null @@ -1,193 +0,0 @@ -# Tools Setup - -## Note - -We recommend using Linux or macOS for this course, we also support Windows but -typically people have more trouble getting everything working correctly on -Windows and it's harder for us to help them since we don't use Windows -ourselves. - -**On Windows, if your username has spaces or special characters in it, the IDE might not -work properly. Please create a new user with a username containing only letters.** - -# Step 1: Create an account on gitlab.epfl.ch - -If you haven't already [log into gitlab](https://gitlab.epfl.ch/users/sign_in) -and fill in [this table](https://docs.google.com/spreadsheets/d/12KvfD_jN5AcApmWhCz7xZmln48fctQOa984RPWrqRkY/edit#gid=0) with your GASPAR and SCIPER number to initialize your GitLab repository for the course. Do this as soon as possible because it will take some time between the account creation and the lab submission system working for your account. - -## Step 2: Installing the Java Development Kit (JDK) and sbt via coursier - -We will use coursier to install the correct version of -Java as well as the sbt build tool: - -### On Linux and macOS - -```shell -curl -fLo cs https://git.io/coursier-cli-"$(uname | tr LD ld)" -``` -```shell -chmod +x cs -``` -```shell -./cs setup -y --jvm 8 --apps cs,sbt -``` - -Please reboot after this point. - -### On Windows - -Download and install both the [Visual C++ 2010 SP1 Redistributable -Package](https://www.microsoft.com/en-us/download/details.aspx?id=26999) and [Visual C++ 2015 Redistributable Update](https://www.microsoft.com/en-us/download/details.aspx?id=52685) (click -on "Download" then select "vcredist_x64.exe" and click "Next"). - -Open `cmd.exe` (and not powershell) - -First, make sure that you are not in the `System32` directory, instead you -should be in `C:\Users\yourusername`. If you are in `System32` you will need to -change directory to your user directory every time you start a terminal by -running: -```shell -cd %USERPROFILE% -``` - -Now assuming that you're in the correct directory you can run: - -```shell -bitsadmin /transfer cs-cli https://github.com/coursier/launchers/raw/master/cs-x86_64-pc-win32.zip "%cd%\cs.zip" -``` -```shell -tar -xf cs.zip -``` -```shell -move cs-x86_64-pc-win32.exe cs.exe -``` -```shell -.\cs setup -y --jvm 8 --apps cs,sbt -``` - -(This command might cause your anti-virus to misidentify cs.exe as a virus, -please override that, that might require temporarily turning off your anti-virus -during this setup). - -If this command fails with `Error running powershell script`, use the following -alternative instructions (if the command didn't fail, continue to the next -step): - -1. Run `.\cs setup --jvm 8 --apps cs,sbt`, at every question answer "n" and - press Enter. -2. The last question should look like "Should we add `C:\...\bin` to your PATH?", - please copy the `C:\...\bin` part here. -3. Edit the Path environment variable and paste the path you just copied to it, see - https://www.architectryan.com/2018/08/31/how-to-change-environment-variables-on-windows-10/ - and make sure the path you're adding is the first entry in the Path environment - variable. -4. Start a **new** cmd.exe and continue with the rest of the instructions - -**In case of errors please ask on Discord or Gitlab issues for help, but don't -try to run commands as Administrator as this will likely cause further issues!** - -Please close this terminal and open a new one after this point. - -## Step 5: Installing git - -git is a version control system. - -### On Ubuntu and Debian - -```shell -sudo apt update && sudo apt install git -``` - -### On macOS - -First, install the Homebrew package manager: - -```shell -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -``` - -Use Homebrew to install git: - -```shell -brew install git -``` - -### On Windows - -Download and install git from [https://git-scm.com/downloads](https://git-scm.com/downloads). -Once git is installed, open a **new** terminal and run: - -```shell -git config --global core.autocrlf false -``` - -If this command worked it will not print anything. - -## Step 6: Installing Code - -Visual Studio Code is the IDE we strongly recommend using for this class (you are free to use any editor you want, but we won't don't have the resources to help you configure it for Scala). - -### On Linux - -See [https://code.visualstudio.com/docs/setup/linux](https://code.visualstudio.com/docs/setup/linux) - -### On macOS - -If you don't already have Code installed: -```shell -brew install --cask visual-studio-code -``` -If it was already installed before, you will need to [enable launching it from the -command line](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line) - -### On Windows - -See [https://code.visualstudio.com/docs/setup/windows](https://code.visualstudio.com/docs/setup/windows). -Make sure that the checkbox "Add to PATH (available after restart)" in the -installer is checked. - -## Step 7: Installing the Scala support for Code - -Open a **new** terminal and run: -```scala -code --install-extension lampepfl.dotty-syntax -``` - -If you're on Windows and the command is not found, try closing and restarting -the terminal, if that doesn't work - -## Step 8: Generate a public/private SSH key pair - -To submit labs, you will need an SSH key. If you don't already have one, here's how to generate it: - -### Step 8.1: Installing OpenSSH - -#### On Ubuntu and Debian - -```shell -sudo apt update && sudo apt install openssh-client -``` - -#### On macOS - -Nothing to do, OpenSSH is pre-installed - -#### On Windows - -Follow the instructions under "Enable OpenSSH Client in Windows 10" on -[https://winaero.com/blog/enable-openssh-client-windows-10/](https://winaero.com/blog/enable-openssh-client-windows-10/) - -### Step 8.2: Generating the key pair - -Please follow [this tutorial](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) to generate a new SSH key and add it to the ssh-agent (except the last step: you should instead add the key to Gitlab as described below). This [video](https://youtu.be/_RsP81Et12s?t=67) (from 1:07 to 4:05) might also help. - -### Step 8.3: Adding your public key on Gitlab - -To be able to push your code, you'll need to add the public part of your key on Gitlab: -- Go to [gitlab.epfl.ch](https://gitlab.epfl.ch), log in with your EPFL account -- Go to [gitlab.epfl.ch/-/profile/keys](https://gitlab.epfl.ch/-/profile/keys) and copy-paste the content of the `id_rsa.pub` file created by the `ssh-keygen` command you just ran (when the command was ran it printed the location where this file was saved). -- Press `Add key` - -## Step 9: Follow the example lab - -Time to do the [example lab](example-lab.md)! diff --git a/previous-exams/2016-final-exam.pdf b/previous-exams/2016-final-exam.pdf deleted file mode 100644 index f9c52136bcc99d615dc3b20728873a3ed5a56705..0000000000000000000000000000000000000000 Binary files a/previous-exams/2016-final-exam.pdf and /dev/null differ diff --git a/previous-exams/2016-final-solution.pdf b/previous-exams/2016-final-solution.pdf deleted file mode 100644 index c4d0d24f13a3e75ace57a30f7d4b118ed7b1d174..0000000000000000000000000000000000000000 Binary files a/previous-exams/2016-final-solution.pdf and /dev/null differ diff --git a/previous-exams/2016-midterm-exam.pdf b/previous-exams/2016-midterm-exam.pdf deleted file mode 100644 index 7dddee4ebf81c8eeeb4d0965cc12a9fd555dae16..0000000000000000000000000000000000000000 Binary files a/previous-exams/2016-midterm-exam.pdf and /dev/null differ diff --git a/previous-exams/2016-midterm-solution.pdf b/previous-exams/2016-midterm-solution.pdf deleted file mode 100644 index 3591e766f6cb1dff3d8cc25cdfcd19dae2c16d60..0000000000000000000000000000000000000000 Binary files a/previous-exams/2016-midterm-solution.pdf and /dev/null differ diff --git a/previous-exams/2017-final-exam.pdf b/previous-exams/2017-final-exam.pdf deleted file mode 100644 index ffc9d2cbcd1034c892ed84023caad6b62539e823..0000000000000000000000000000000000000000 Binary files a/previous-exams/2017-final-exam.pdf and /dev/null differ diff --git a/previous-exams/2017-final-solution.pdf b/previous-exams/2017-final-solution.pdf deleted file mode 100644 index 9afc90c86ec5bc2a6acda029301cb1bcaa20a27a..0000000000000000000000000000000000000000 Binary files a/previous-exams/2017-final-solution.pdf and /dev/null differ diff --git a/previous-exams/2017-midterm-exam.pdf b/previous-exams/2017-midterm-exam.pdf deleted file mode 100644 index 664f251b603842a477de71864497785d17e1415d..0000000000000000000000000000000000000000 Binary files a/previous-exams/2017-midterm-exam.pdf and /dev/null differ diff --git a/previous-exams/2017-midterm-solution.pdf b/previous-exams/2017-midterm-solution.pdf deleted file mode 100644 index 1d33d5ca6519200954a86a26f9fe9cb768a78c56..0000000000000000000000000000000000000000 Binary files a/previous-exams/2017-midterm-solution.pdf and /dev/null differ diff --git a/previous-exams/2018-final-exam.pdf b/previous-exams/2018-final-exam.pdf deleted file mode 100644 index 09c41d4f4d47eb59eb5f4a01c34e47caa933d3ca..0000000000000000000000000000000000000000 Binary files a/previous-exams/2018-final-exam.pdf and /dev/null differ diff --git a/previous-exams/2018-final-solution.pdf b/previous-exams/2018-final-solution.pdf deleted file mode 100644 index 451d2dbd8dbe6824144428d6cb8640cee8ccd40d..0000000000000000000000000000000000000000 Binary files a/previous-exams/2018-final-solution.pdf and /dev/null differ diff --git a/previous-exams/2018-midterm-exam.pdf b/previous-exams/2018-midterm-exam.pdf deleted file mode 100644 index 7f2ece022e95aeb6b116a138c58dcaadea9fc7d1..0000000000000000000000000000000000000000 Binary files a/previous-exams/2018-midterm-exam.pdf and /dev/null differ diff --git a/previous-exams/2018-midterm-solution.pdf b/previous-exams/2018-midterm-solution.pdf deleted file mode 100644 index e0c1d4a8d2227310380a8afedbb92934e1ec8bd2..0000000000000000000000000000000000000000 Binary files a/previous-exams/2018-midterm-solution.pdf and /dev/null differ diff --git a/previous-exams/2019-final-exam.pdf b/previous-exams/2019-final-exam.pdf deleted file mode 100644 index 6f5c49ae36d41ba823f8e01d9d05df28ddb612a7..0000000000000000000000000000000000000000 Binary files a/previous-exams/2019-final-exam.pdf and /dev/null differ diff --git a/previous-exams/2019-final-solution.pdf b/previous-exams/2019-final-solution.pdf deleted file mode 100644 index 630dfa0bc9ddcdc7e26b93e3656fabcc9fefb379..0000000000000000000000000000000000000000 Binary files a/previous-exams/2019-final-solution.pdf and /dev/null differ diff --git a/previous-exams/2019-midterm-exam.pdf b/previous-exams/2019-midterm-exam.pdf deleted file mode 100644 index bcd12b5e02788e1aa4cd3d1da1bb2bb038de234d..0000000000000000000000000000000000000000 Binary files a/previous-exams/2019-midterm-exam.pdf and /dev/null differ diff --git a/previous-exams/2019-midterm-solution.pdf b/previous-exams/2019-midterm-solution.pdf deleted file mode 100644 index 707d69a5ecac42af56e4c39cdcf3237be9676aff..0000000000000000000000000000000000000000 Binary files a/previous-exams/2019-midterm-solution.pdf and /dev/null differ diff --git a/previous-exams/2020-final-exam/q10.md b/previous-exams/2020-final-exam/q10.md deleted file mode 100644 index 80ee295c48d14e2fc69a1e0a7723dc1c86a47347..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q10.md +++ /dev/null @@ -1,71 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q10 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q10 -cd cs210-q10 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -You are given the method `fImperative`, which from a given list of tuples generates a list of integers, such that each tuple in the input list is transformed into several consecutive integer elements. The number and values of groups of consecutive elements are determined by the first and second element of the corresponding tuple, respectively. In cases where the specified number of consecutive elements is less than zero, it is considered to be zero. - -For example, for the given input list: `((-1,5),(2,7),(1,2))` the output list should be: `(7,7,2)`. - - -```scala - def fImperative(elems: List[(Int, Int)]): List[Int] = { - var i = 0 - var res: List[Int] = List() - - while (i < elems.size) { - var j = 0 - var cnt = l(i)._1 - while (j < cnt) { - res = elems(i)._2 :: res - j = j + 1 - } - i = i + 1 - } - res.reverse - } -``` - -This solution uses var-s and while loops so it is not in the spirit of functional programming. Your task is to write a new implementation of this method in a purely functional way, using pattern matching and a limited set of existing list methods given in the appendix. Your solution should produce the same result as the given imperative method, but without imperative constructs such as var and while. You may define and implement additional methods. Correct solutions will be given a full score even if they are not tail-recursive. - -In this exercise you are only allowed to use existing list methods which are listed in the appendix. - -`def f(elems: List[(Int, Int)]): List[Int] = ???` - -# Appendix - -Here are the methods that you are allowed to use on `List[A]`: - -`xs.head: A`: returns the first element of the list. Throws an exception if the list is empty. - -`xs.tail: List[A]`: returns the list `xs` without its first element. Throws an exception if the list is empty. - -`xs.isEmpty: Boolean`: returns `true` if the list does not contain any elements, `false` otherwise. - -`x :: (xs: List[A]): List[A]`: prepends the element `x` to the left of `xs`, returning a `List[A]`. - -`xs.reverse: List[A]`: reverses the elements of the list `xs`. \ No newline at end of file diff --git a/previous-exams/2020-final-exam/q16.md b/previous-exams/2020-final-exam/q16.md deleted file mode 100644 index 1e85b74136d6a5e7de3a442268f6e570da5453a7..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q16.md +++ /dev/null @@ -1,48 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q16 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q16 -cd cs210-q16 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise 16: For-comprehensions - -You are given two classes (`Library` and `Book` which are defined below) and the method `f`, which from a given list of libraries generates a list of Scala book titles with their edition and location. Books might be in more than one location. Two editions of a book are considered distinct. - - -```scala -case class Library(books: List[Book], location: String) -case class Book(title: String, publisher: String, editions: List[Int]) - -def f(libraries: List[Library]): List[(String, Int, String)] = { - for { - library <- libraries - book <- library.books - if book.title.contains("Scala") - if !book.title.contains("La Scala") // List books about `Scala` but not books about `La Scala` opera - edition <- book.editions - } yield (book.title, edition, library.location) -} -``` - -Your task is to rewrite the method `f` to use `map`, `flatMap` and `withFilter` instead of the for-comprehension. The resulting method should of course have the same result as the for-comprehension above. diff --git a/previous-exams/2020-final-exam/q17.md b/previous-exams/2020-final-exam/q17.md deleted file mode 100644 index 6c7b954133f97da6450d6e28c16ac368dd62f241..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q17.md +++ /dev/null @@ -1,48 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q17 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q17 -cd cs210-q17 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise 17: For-comprehensions - -You are given two classes (`Library` and `Book` which are defined below) and the method `f`, which from a given list of libraries and a list of publishers generates a list with the book count of each publisher in each library. Book count results are a triple containing the publisher, the library location, and the number of books. If a library does not contain books from a publisher then the count is not included in the result. - - -```scala -case class Library(books: List[Book], location: String) -case class Book(title: String, authors: List[String], publisher: String, year: Int) - -def f(libraries: List[Library], publishers: List[String]): List[(String, String, Int)] = { - for { - publisher <- publishers - library <- libraries - if numBooksPublishedBy(library.books, publisher) != 0 // Don't list if there are no books in the library - } yield (publisher, library.location, numBooksPublishedBy(library.books, publisher)) -} - -def numBooksPublishedBy(books: List[Book], publisher: String): Int = ... -``` - -Your task is to rewrite the method `f` to use `map`, `flatMap` and `withFilter` instead of the for-comprehension. The resulting method should of course have the same result as the for-comprehension above. diff --git a/previous-exams/2020-final-exam/q18.md b/previous-exams/2020-final-exam/q18.md deleted file mode 100644 index 4e9747648221ed5fc52e406fea78905a6cd8f636..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q18.md +++ /dev/null @@ -1,46 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q18 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q18 -cd cs210-q18 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise 18: For-comprehensions - -You are given the class `Book` (which is defined below) and the method `f`, which from a given list of books, a predicate on years and a predicate on authors will return tuples with the author and name of the books for which the predicates hold. - - -```scala -case class Book(title: String, authors: List[String], year: Int) - -def f(books: List[Book], yearPred: Int => Boolean, authorPred: String => Boolean): List[(String, String)] = { - for { - book <- books - if yearPred(book.year) - author <- book.authors - if authorPred(author) - } yield (author, book.title) -} -``` - -Your task is to rewrite the method `f` to use `map`, `flatMap` and `withFilter` instead of the for-comprehension. The resulting method should of course have the same result as the for-comprehension above. diff --git a/previous-exams/2020-final-exam/q19.md b/previous-exams/2020-final-exam/q19.md deleted file mode 100644 index 6dc1f3873369b3f6c9202acfe62facf4c4032b78..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q19.md +++ /dev/null @@ -1,51 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q19 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q19 -cd cs210-q19 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -You are given four classes (`Client`, `Purchase`, `Store` and `DataBase` which are defined below) and the method `f`. The method `f` lists all the purchases location and amount performed by a client with name `clientName`. - -```scala -case class Client(id: Int, name: String) -case class Purchase(clientId: Int, storeId: Int, amount: Double) -case class Store(id: Int, location: String) - -case class DataBase(clients: List[Client], purchases: List[Purchase], stores: List[Store]) - -def purchasesOf(db: DataBase, clientName: String): List[(String, Double)] = { - for { - client <- db.clients - if client.name == clientName - purchase <- db.purchases - if purchase.clientId == client.id - store <- db.stores - if store.id == purchase.storeId - } yield (store.location, purchase.amount) -} -``` - -Your task is to rewrite the method `f` to use `map`, `flatMap` and `withFilter` instead of the for-comprehension. The resulting method should of course have the same result as the for-comprehension above. diff --git a/previous-exams/2020-final-exam/q20.md b/previous-exams/2020-final-exam/q20.md deleted file mode 100644 index 583c7d3cf9c5dad8fe2467a16493de946ef200e6..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q20.md +++ /dev/null @@ -1,49 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q20 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q20 -cd cs210-q20 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -You are given three classes (`Client`, `Purchase` and `DataBase` which are defined below) and the method `f`. The method `f` lists all the purchases client's ages and amount. Purchases for clients with no age set in the database are ignored. - - -```scala -case class Client(id: Int, name: String, age: Option[Int]) -case class Purchase(clientId: Int, amount: Double) - -case class DataBase(clients: List[Client], purchases: List[Purchase]) - -def purchasesClientAgeAndAmounts(db: DataBase): List[(Int, Double)] = { - for { - client <- db.clients - age <- client.age.toList - purchase <- db.purchases - if purchase.clientId == client.id - } yield (age, purchase.amount) -} -``` - -Your task is to rewrite the method `f` to use `map`, `flatMap` and `withFilter` instead of the for-comprehension. The resulting method should of course have the same result as the for-comprehension above. diff --git a/previous-exams/2020-final-exam/q21.md b/previous-exams/2020-final-exam/q21.md deleted file mode 100644 index 9c3749ef7d7b93f80f5d585f0cbdeeb9ead920c4..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q21.md +++ /dev/null @@ -1,38 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q21 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q21 -cd cs210-q21 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -Define the sequence of all the squares written backwards: - -``` -1, 4, 9, 61, 52, 63, 94, 46, 18, 1, 121, 441, 961, 691, 522, 652, 982, 423, 163, 4, 144, 484, 925, 675, 526, ... -``` - -This sequence is infinite and must be implemented as a lazy list of integers. - -For the purpose of this exercise, you should ignore the limitations of 32-bit integers. diff --git a/previous-exams/2020-final-exam/q22.md b/previous-exams/2020-final-exam/q22.md deleted file mode 100644 index 93403c0b7063257005f1f166360384d3648cd602..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q22.md +++ /dev/null @@ -1,46 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q22 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q22 -cd cs210-q22 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -Define the sequence of all numbers that read the same upside down (180° rotation) on a seven-segment display: - -``` -0, 1, 2, 5, 8, 11, 22, 55, 69, 88, 96, 101, 111, 121, 151, 181, 202, 212, 222, 252, 282, 505, 515, 525, 555, ... -``` - -For reference, digits on a seven-segment display are rendered as follows: - -``` - _ _ _ _ _ _ _ _ -| | | _| _| |_| |_ |_ | |_| |_| -|_| | |_ _| | _| |_| | |_| _| -``` - -This sequence is infinite and must be implemented as a lazy list of integers. - -For the purpose of this exercise, you should ignore the limitations of 32-bit integers. diff --git a/previous-exams/2020-final-exam/q23.md b/previous-exams/2020-final-exam/q23.md deleted file mode 100644 index 1be3b4fdd4d3ecee5e1bcfb6d059fda441471097..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q23.md +++ /dev/null @@ -1,38 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q23 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q23 -cd cs210-q23 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -Define the sequence of all numbers divisible by 7 that read the same backward as forward: - -``` -7, 77, 161, 252, 343, 434, 525, 595, 616, 686, 707, 777, 868, 959, 1001, 1771, 2002, 2772, 3003, 3773, 4004, 4774, 5005, 5775, 6006, ... -``` - -This sequence is infinite and must be implemented as a lazy list of integers. - -For the purpose of this exercise, you should ignore the limitations of 32-bit integers. diff --git a/previous-exams/2020-final-exam/q24.md b/previous-exams/2020-final-exam/q24.md deleted file mode 100644 index c1a7a9e5b4c0faf25cbaacc7ec76dfef0318b0dd..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q24.md +++ /dev/null @@ -1,48 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q24 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q24 -cd cs210-q24 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -Pell numbers are defined by the following equations: - -``` -a(0) = 0 -a(1) = 1 -a(n) = 2 * a(n - 1) + a(n - 2) (for n > 1) -``` - -Here are the first 25 Pell numbers: - -``` -0, 1, 2, 5, 12, 29, 70, 169, 408, 985, 2378, 5741, 13860, 33461, 80782, 195025, 470832, 1136689, 2744210, 6625109, 15994428, 38613965, 93222358, 225058681, 543339720 -``` - -Implement this sequence as an infinite lazy list of integers. - -There are many ways to correctly solve this problem, however some implementations run in an exponential time, so be careful, an inefficient implementation might result in a timeout during the grading process. - -For the purpose of this exercise, you should ignore the limitations of 32-bit integers. diff --git a/previous-exams/2020-final-exam/q25.md b/previous-exams/2020-final-exam/q25.md deleted file mode 100644 index 0d330d68f1d5479d13bbeda576d194abe08cece7..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q25.md +++ /dev/null @@ -1,66 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q25 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q25 -cd cs210-q25 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -Consider the infinite integer sequences `a(n)` defined by the following equations (for a given initial positive integer `k`): - -``` -a(0) = k -a(n+1) = a(n) / 2 if a(n) is even (for n >= 0) -a(n+1) = 3 * a(n) + 1 if a(n) is odd (for n >= 0) -``` - -Here are the first 16 numbers of that sequence for `k = 10`: - -``` -10, 5, 16, 8, 4, 2, 1, 4, 2, 1, 4, 2, 1, 4, 2, 1, ... -``` - -For `k = 11`: - -``` -11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1, 4, ... -``` - -And for `k = 12`: - -``` -12, 6, 3, 10, 5, 16, 8, 4, 2, 1, 4, 2, 1, 4, 2, 1, ... -``` - -As you can see, these sequences all converge to `1` and then loop with the same pattern (`1, 4, 2, 1,`). - -There is a famous mathematical conjecture stating that for any initial positive integer `k` the resulting sequence always converges to `1`. - -In this exercise, your task is to write a lazy list implementation of these integer sequences. Your sequences should stop when the first `1` is reached, that is: - -- `(k = 10) 10, 5, 16, 8, 4, 2, 1` -- `(k = 11) 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1` -- `(k = 12) 12, 6, 3, 10, 5, 16, 8, 4, 2, 1` - -For the purpose of this exercise, you should ignore the limitations of 32-bit integers. diff --git a/previous-exams/2020-final-exam/q6.md b/previous-exams/2020-final-exam/q6.md deleted file mode 100644 index 9adf44af71c0b04ff341f130493bfe854bf4f6a0..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q6.md +++ /dev/null @@ -1,82 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q6 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q6 -cd cs210-q6 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -You are given the method `fImperative`, which from a given list of characters, representing a word, generates a list with one letter removed, such that the resulting word is lexicographically largest among all the options. - -For example, for the given list of characters: `('d', 'b', 'c')` there are three possible results after removing one letter: `(b', 'c')`, `('d', 'c')` and `('d', 'b')`. Word `('d', 'c')` is lexicographically largest among the options, so this is the result of our method for this input example. - -```scala - def fImperative(chars: List[Char]): List[Char] = { - var i = 0 - var n = chars.size - var res: List[Char] = List() - - while (i < n - 1 && chars(i) >= chars(i + 1)) { - res = chars(i) :: res - i = i + 1 - } - - i = i + 1 - - while (i < n) { - res = chars(i) :: res - i = i + 1 - } - - res.reverse - } -``` - -This solution uses var-s and while loops so it is not in the spirit of functional programming. Your task is to write a new implementation of this method in a purely functional way, using pattern matching and a limited set of existing list methods given in the appendix. Your solution should produce the same result as the given imperative method, but without imperative constructs such as var and while. You may define and implement additional methods. Correct solutions will be given a full score even if they are not tail-recursive. - -In this exercise you are only allowed to use existing list methods which are listed in the appendix. - -`def f(chars: List[Char]): List[Char] = ???` - -# Appendix - -Here are the methods that you are allowed to use on `List[A]`: - -`xs.head: A`: returns the first element of the list. Throws an exception if the list is empty. - -`xs.tail: List[A]`: returns the list `xs` without its first element. Throws an exception if the list is empty. - -`xs.isEmpty: Boolean`: returns `true` if the list does not contain any elements, `false` otherwise. - -`x :: (xs: List[A]): List[A]`: prepends the element `x` to the left of `xs`, returning a `List[A]`. - -`xs.reverse: List[A]`: reverses the elements of the list `xs`. - - - - - - - - diff --git a/previous-exams/2020-final-exam/q7.md b/previous-exams/2020-final-exam/q7.md deleted file mode 100644 index a37cbaad7df1ddae2d864a75cc485dd644ac04f2..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q7.md +++ /dev/null @@ -1,72 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q7 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q7 -cd cs210-q7 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -You are given the method `fImperative`, which from a given list of integers generates a list of tuples, such that each tuple contains number and value of equal consecutive elements of the input list. - -For example, for the given input list: `(2,2,2,7,7,2)` the output list should be: `((3,2),(2,7),(1,2))`. - - -```scala - def fImperative(nums: List[Int]): List[(Int, Int)] = { - var cnt = 1 - var i = 0 - var res: List[(Int, Int)] = List() - - while (i < nums.length - 1) { - if (nums(i) == nums(i + 1)) cnt = cnt + 1 - else { - res = (cnt, nums(i)) :: res - cnt = 1 - } - i = i + 1 - } - if(nums.isEmpty) Nil - else ((cnt, nums(nums.length - 1)) :: res).reverse - } -``` - -This solution uses var-s and while loops so it is not in the spirit of functional programming. Your task is to write a new implementation of this method in a purely functional way, using pattern matching and a limited set of existing list methods given in the appendix. Your solution should produce the same result as the given imperative method, but without imperative constructs such as var and while. You may define and implement additional methods. Correct solutions will be given a full score even if they are not tail-recursive. - -In this exercise you are only allowed to use existing list methods which are listed in the appendix. - -`def f(l: List[Int]): List[(Int, Int)] = ???` - -# Appendix - -Here are the methods that you are allowed to use on `List[A]`: - -`xs.head: A`: returns the first element of the list. Throws an exception if the list is empty. - -`xs.tail: List[A]`: returns the list `xs` without its first element. Throws an exception if the list is empty. - -`xs.isEmpty: Boolean`: returns `true` if the list does not contain any elements, `false` otherwise. - -`x :: (xs: List[A]): List[A]`: prepends the element `x` to the left of `xs`, returning a `List[A]`. - -`xs.reverse: List[A]`: reverses the elements of the list `xs`. diff --git a/previous-exams/2020-final-exam/q8.md b/previous-exams/2020-final-exam/q8.md deleted file mode 100644 index 40d77f16ca8587f21fc16edcb5404224aff7c5f7..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q8.md +++ /dev/null @@ -1,76 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q8 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q8 -cd cs210-q8 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -You are given the method `fImperative`, which from a given list of integers, which represents heights of people standing in a bank queue, generates a list of the same size, such that the value of each element is the number of people visible to the corresponding person in the input list. A person is considered visible to another person if they are in front of them in the queue, and there is no taller (or equally tall) person in between. You can assume that all the elements of the input list are natural numbers. - -For example, for the given input list: `(182, 160, 180, 178)` the output list should be `(0, 1, 2, 2)`. - -```scala - def fImperative(nums: List[Int]): List[Int] = { - var i = 0 - var j = 0 - var res: List[Int] = List() - - while (i < nums.size) { - var max = -1 - var cnt = 0 - j = i - 1 - while (j >= 0) { - if(nums(j) > max) { - cnt = cnt + 1 - max = nums(j) - } - j = j - 1 - } - res = cnt :: res - i = i + 1 - } - res.reverse - } -``` - -This solution uses var-s and while loops so it is not in the spirit of functional programming. Your task is to write a new implementation of this method in a purely functional way, using pattern matching and a limited set of existing list methods given in the appendix. Your solution should produce the same result as the given imperative method, but without imperative constructs such as var and while. You may define and implement additional methods. Correct solutions will be given a full score even if they are not tail-recursive. - -In this exercise you are only allowed to use existing list methods which are listed in the appendix. - -`def f(nums: List[Int]): List[Int] = ???` - -# Appendix - -Here are the methods that you are allowed to use on `List[A]`: - -`xs.head: A`: returns the first element of the list. Throws an exception if the list is empty. - -`xs.tail: List[A]`: returns the list `xs` without its first element. Throws an exception if the list is empty. - -`xs.isEmpty: Boolean`: returns `true` if the list does not contain any elements, `false` otherwise. - -`x :: (xs: List[A]): List[A]`: prepends the element `x` to the left of `xs`, returning a `List[A]`. - -`xs.reverse: List[A]`: reverses the elements of the list `xs`. diff --git a/previous-exams/2020-final-exam/q9.md b/previous-exams/2020-final-exam/q9.md deleted file mode 100644 index a953dee248f11c4bb5af288615e106d31114a205..0000000000000000000000000000000000000000 --- a/previous-exams/2020-final-exam/q9.md +++ /dev/null @@ -1,72 +0,0 @@ -# Setup - -You can use the following commands to make a fresh clone of your repository: - -``` -git clone -b q9 git@gitlab.epfl.ch:lamp/students-repositories-fall-2021/cs210-GASPAR.git cs210-q9 -cd cs210-q9 -``` - -You can always refer to: - * [the example guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/example-lab.md) on the development workflow. - * [this guide](https://gitlab.epfl.ch/lamp/cs210/blob/master/labs/grading-and-submission.md) for details on the submission system. - * [The documentation of the Scala standard library](https://www.scala-lang.org/files/archive/api/2.13.3) - * [The documentation of the Java standard - library](https://docs.oracle.com/en/java/javase/15/docs/api/index.html) - -**If you have issues with the IDE, try [reimporting the build](https://gitlab.epfl.ch/lamp/cs210/-/blob/master/labs/example-lab.md#ide-features-like-type-on-hover-or-go-to-definition-do-not-work), if you still have problems, use `compile` in sbt instead.** - -# Be functional! - -This course is about **functional** programming, therefore you're not allowed to use the following -constructs in this assignment: -- `var` -- `while` -- `return` -- Any class in the `scala.collection.mutable` package - -# Exercise - -You are given the method `fImperative`, which computes its result from a given list of distinct characters `l1`, which represents a secret word, and another list `l2`, which represents a guess word. The result of the method is a list of characters from the secret word that are present in the guess word (in order of appearance from the secret word and without duplicate letters). - -For example, for the given secret word: `('o','t','h','e','r')` and the guess word: `('t','a','r','t','s')` the output list should be: `('t','r')`. - -```scala - def fImperative(l1: List[Char], l2: List[Char]): List[Char] = { - var i = 0 - var res: List[Char] = List() - - while (i < l1.size) { - var j = 0 - while (j < l2.size) { - if(l2(j) == l1(i)) { - res = l2(j) :: res - j = l2.size - } - j = j + 1 - } - i = i + 1 - } - res.reverse - } -``` - -This solution uses var-s and while loops so it is not in the spirit of functional programming. Your task is to write a new implementation of this method in a purely functional way, using pattern matching and a limited set of existing list methods given in the appendix. Your solution should produce the same result as the given imperative method, but without imperative constructs such as var and while. You may define and implement additional methods. Correct solutions will be given a full score even if they are not tail-recursive. - -In this exercise you are only allowed to use existing list methods which are listed in the appendix. - -`def f(l1: List[Char], l2: List[Char]): List[Char] = ???` - -# Appendix - -Here are the methods that you are allowed to use on `List[A]`: - -`xs.head: A`: returns the first element of the list. Throws an exception if the list is empty. - -`xs.tail: List[A]`: returns the list `xs` without its first element. Throws an exception if the list is empty. - -`xs.isEmpty: Boolean`: returns `true` if the list does not contain any elements, `false` otherwise. - -`x :: (xs: List[A]): List[A]`: prepends the element `x` to the left of `xs`, returning a `List[A]`. - -`xs.reverse: List[A]`: reverses the elements of the list `xs`. diff --git a/previous-exams/2021-final-dryrun-exam.pdf b/previous-exams/2021-final-dryrun-exam.pdf deleted file mode 100644 index 956cda0de02902deb104a911d5a10786d9194ed6..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-final-dryrun-exam.pdf and /dev/null differ diff --git a/previous-exams/2021-final-dryrun-solution.pdf b/previous-exams/2021-final-dryrun-solution.pdf deleted file mode 100644 index f420140c35cb384e558c6b34d7ee398a895e66a0..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-final-dryrun-solution.pdf and /dev/null differ diff --git a/previous-exams/2021-midterm-exam.pdf b/previous-exams/2021-midterm-exam.pdf deleted file mode 100644 index e3a5167b1ec72fa1348016504b02f2955f281781..0000000000000000000000000000000000000000 Binary files a/previous-exams/2021-midterm-exam.pdf and /dev/null differ diff --git a/previous-exams/2021-midterm-solution.md b/previous-exams/2021-midterm-solution.md deleted file mode 100644 index 9231837414c992a5d1581b9a61e31424bf5e099d..0000000000000000000000000000000000000000 --- a/previous-exams/2021-midterm-solution.md +++ /dev/null @@ -1,337 +0,0 @@ -# 2021 Midterm, Solutions - -## Exercise 1 - -```scala -trait Tree[T]: - def height: Int = this match - case EmptyTree(_) => 0 - case Node(left, _, right, _) => Math.max(left.height, right.height) + 1 - - def isBalanced: Boolean = this match - case EmptyTree(_) => true - case Node(left, _, right, _) => left.isBalanced && right.isBalanced && Math.abs(left.height - right.height) <= 1 - -case class EmptyTree[T](leq: (T, T) => Boolean) extends Tree[T] -case class Node[T](left: Tree[T], elem: T, right: Tree[T], leq: (T, T) => Boolean) -extends Tree[T] -``` - -<details> - -<summary>Tests</summary> - -```scala -def intLeq(a: Int, b: Int) = a <= b - -val exTree1 = Node( - Node( - Node(EmptyTree(intLeq), 1, EmptyTree(intLeq), intLeq), - 2, - Node(EmptyTree(intLeq), 3, EmptyTree(intLeq), intLeq), - intLeq - ), - 5, - Node( - Node(EmptyTree(intLeq), 7, EmptyTree(intLeq), intLeq), - 9, - Node( - Node(EmptyTree(intLeq), 10, EmptyTree(intLeq), intLeq), - 15, - Node(EmptyTree(intLeq), 25, EmptyTree(intLeq), intLeq), - intLeq - ), - intLeq - ), - intLeq -) - -val exTree2 = Node( - Node( - Node( - Node(EmptyTree(intLeq), 25, EmptyTree(intLeq), intLeq), - 15, - Node(EmptyTree(intLeq), 10, EmptyTree(intLeq), intLeq), - intLeq - ), - 9, - Node(EmptyTree(intLeq), 7, EmptyTree(intLeq), intLeq), - intLeq - ), - 5, - Node( - Node(EmptyTree(intLeq), 3, EmptyTree(intLeq), intLeq), - 2, - Node(EmptyTree(intLeq), 1, EmptyTree(intLeq), intLeq), - intLeq - ), - intLeq -) - -val tree3 = Node( - Node( - Node( - Node(EmptyTree(intLeq), 25, EmptyTree(intLeq), intLeq), - 15, - Node(EmptyTree(intLeq), 10, EmptyTree(intLeq), intLeq), - intLeq - ), - 9, - Node(EmptyTree(intLeq), 7, EmptyTree(intLeq), intLeq), - intLeq - ), - 5, - EmptyTree(intLeq), - intLeq -) - -assert(exTree1.height == 4) -assert(exTree2.height == 4) -assert(EmptyTree(intLeq).height == 0) -assert(exTree1.isBalanced) -assert(exTree2.isBalanced) -assert(!tree3.isBalanced) -``` - -</details> - -## Exercise 2 - -```scala -enum Expr: - case Var(name: String) - case Op(name: String, args: List[Expr]) - -import Expr._ - -final case class UnknownVarException(name: String) extends Exception -final case class UnknownOpException(name: String) extends Exception -``` - -There was multiple correct solutions. Here two possible solutions: - -```scala -def eval1(e: Expr, context: Map[Var, Int]): Int = e match - case Var(name) => context.get(Var(name)) match - case Some(n) => n - case _ => throw UnknownVarException(name) - case Op(name, args) => - val nargs = args.map(eval1(_, context)) - name match - case "*" => nargs.foldLeft(1)(_ * _) - case "+" => nargs.foldLeft(0)(_ + _) - case _ => throw UnknownOpException(name) - -def eval2(e: Expr, context: Map[Var, Int]): Int = e match - case sym: Var if context.contains(sym) => context(sym) - case sym: Var => throw UnknownVarException(sym.name) - case Op("*", args) => args.foldLeft(1)(_ * eval2(_, context)) - case Op("+", args) => args.foldLeft(0)(_ + eval2(_, context)) - case Op(name, _) => throw UnknownOpException(name) -``` - -**Comments** -- A lot of you assumed that the arguments of `Op`s can only be `Var`s, but these can be `Op`s as well as in `Op("*", List(Op("+", List(Var("x"), Var("x"))), Var("y")))`, so the function needs to call itself _recursively_ for each operation argument. -- Minor: `Map[Var, Int]` maps `Var` to `Int`s, so the argument passed to `context.get` must be a `Var`, not a `String`. - -<details> - -<summary>Tests</summary> - -```scala -for eval <- Seq(eval1, eval2) do - assert(eval(Op("+", List()), Map()) == 0) - assert(eval(Op("+", List(Var("x"))), Map(Var("x") -> 2)) == 2) - assert(eval(Op("+", List(Var("x"), Var("y"))), Map(Var("x") -> 2, Var("y") -> 3)) == 5) - assert(eval(Op("*", List()), Map()) == 1) - assert(eval(Op("*", List(Var("x"))), Map(Var("x") -> 2)) == 2) - assert(eval(Op("*", List(Var("x"), Var("y"))), Map(Var("x") -> 2, Var("y") -> 3)) == 6) - assert(eval(Op("*", List(Op("+", List(Var("x"), Var("x"))), Var("y"))), Map(Var("x") -> 2, Var("y") -> 3)) == 12) -``` - -</details> - -## Exercise 3 - -### Exercise 3.1 - -- Type parameter `A` in `map` -- `def map[B >: A](f: B => C): Transform[A, C]` - - <details> - <summary>Full code</summary> - - ```scala mdoc - trait Transform[-A, +B]: - def apply(x: A): B - def map[C](f: B => C): Transform[A, C] - def followedBy[C](t: Transform[B, C]): Transform[A, C] - ``` - - </details> - -### Exercise 3.2 - -``` -Is the following subtype assertion true? yes no - -List[Triangle] <: List[AnyRef] [X] [ ] -List[Shape] <: List[AnyVal] [ ] [X] -List[String] <: List[Shape] [ ] [X] -Transform[Point, Circle] <: Transform[Point, Any] [X] [ ] -Transform[Point, Shape] <: Transform[Shape, Point] [ ] [X] -Transform[Shape, Point] <: Transform[Point, Shape] [X] [ ] -``` - -## Exercise 4 - -Axioms: - -``` -(1) Nil.reverse === Nil - -(2) (x::xs).reverse === xs.reverse ++ (x::Nil) - -(3) (xs++ys)++zs === xs++(ys++zs) - -(4) Nil map f === Nil - -(5) (x::xs) map f === f(x) :: (xs map f) - -(6) Nil ++ ys === ys - -(7) xs ++ Nil === xs - -(8) x::xs ++ ys === x::(xs ++ ys) - -(9) (l1 ++ l2).map(f) === l1.map(f) ++ l2.map(f) -``` - -### Exercise 4.1 - - -``` -We must prove: - -(10) (l1 ++ l2).reverse === l2.reverse ++ l1.reverse - - -By induction on l1: - -- l1 is Nil: - - (Nil ++ l2).reverse === - (6) l2.reverse - - l2.reverse ++ Nil.reverse === - (1) l2.reverse ++ Nil === - (7) l2.reverse - -- l1 is x::xs - - IH: (xs ++ l2).reverse === l2.reverse ++ xs.reverse - - (x::xs ++ l2).reverse === - (8) (x::(xs ++ l2)).reverse === - (2) (xs ++ l2).reverse ++ (x::Nil) === - (IH) l2.reverse ++ xs.reverse ++ x::Nil === - (3) l2.reverse ++ (xs.reverse ++ x::Nil) === - (2) l2.reverse ++ (x::xs).reverse === - l2.reverse ++ l1.reverse -``` - -### Exercise 4.2 - -``` -We must prove: - -(l1 ++ l2).reverse.map(f) === l2.reverse.map(f) ++ l1.reverse.map(f) - - -Direct proof using axiom 10 proved in 4.1: - - (l1 ++ l2).reverse.map(f) = -(10) (l2.reverse ++ l1.reverse).map(f) = -(9) l2.reverse.map(f) ++ l1.reverse.map(f) - - -Or without using axiom 10: - -By induction on l1: - -- l1 is Nil: - - ((l1 ++ l2).reverse).map(f) === - (6) l2.reverse.map.(f) - - l2.reverse.map(f) ++ l1.reverse.map(f) === - (1) l2.reverse.map(f) ++ Nil.map(f) === - (4) l2.reverse.map(f) ++ Nil === - (7) l2.reverse.map(f) - - -- l1 is x::xs - - IH: ((xs ++ l2).reverse).map(f) === l2.reverse.map(f) ++ xs.reverse.map(f) - - ((x::xs) ++ l2).reverse.map(f) === - (8) (x::(xs ++ l2)).reverse.map(f) === - (2) ((xs ++ l2).reverse ++ (x::Nil)).map(f) === - (9) ((xs ++ l2).reverse.map(f)) ++ ((x::Nil).map(f)) === - (IH) l2.reverse.map(f) ++ xs.reverse.map(f) ++ (x::Nil).map(f) === - (3) l2.reverse.map(f) ++ (xs.reverse.map(f) ++ (x::Nil).map(f)) === - (9) l2.reverse.map(f) ++ (xs.reverse ++ x::Nil).map(f)) === - (2) l2.reverse.map(f) ++ ((x::xs).reverse.map(f)) === -``` - -## Exercise 5 - -### Exercise 5.1 - -There was multiple correct solutions: - -```scala -def takeWhileStrictlyIncreasing1(list: List[Int]): List[Int] = list match - case Nil => Nil - case x :: Nil => list - case x1 :: x2 :: xs => if x1 < x2 then x1 :: takeWhileStrictlyIncreasing1(x2 :: xs) else List(x1) - -def takeWhileStrictlyIncreasing2(list: List[Int]): List[Int] = { - def fun(ls: List[Int], last: Int): List[Int] = ls match - case x :: xs if x > last => x :: fun(xs, x) - case _ => Nil - - list match - case x :: xs => x :: fun(xs, x) - case Nil => Nil -} - -def takeWhileStrictlyIncreasing3(list: List[Int]): List[Int] = { - def fun(ls: List[Int], last: Option[Int]): List[Int] = (ls, last) match - case (x :: xs, Some(last)) if x > last => x :: fun(xs, Some(x)) - case (x :: xs, None) => x :: fun(xs, Some(x)) - case _ => Nil - - fun(list, None) -} -``` - - -**Comments** -- It was possible to write a correct implementation using foldLeft. Note that foldLeft traverses the whole list and cannot "early return" like a recursive call. This possible solution was not very clean as it required a flag or a condition to check that foldLeft should do nothing once it passed the first decreasing step. Avoid using foldLeft when you do not need to traverse the whole list every time. -- When we do not ask for a tail recursive implementation, the solution can be more readable without an accumulator. You should favor a simple and readable version. -- The solution `takeWhileStrictlyIncreasing3` uses `Option` and is elaborate. We include this solution for a good example of using `Option` but `takeWhileStrictlyIncreasing2` is simpler and more readable. - -### Exercise 5.2 - -```scala -def increasingSequences(list: List[Int]): List[List[Int]] = list match - case Nil => Nil - case _ => - val prefix = takeWhileStrictlyIncreasing(list) - prefix :: increasingSequences(list.drop(prefix.length)) -``` - -**Comments** -- It is important to store `prefix` to avoid calling twice `takeWhileStrictlyIncreasing`. -- In the empty list case, some students made the confusion of returning a list containing the empty list. In this case, we have: `List[List[Int]]() == Nil != List(Nil) == List(List[Int]())`. \ No newline at end of file diff --git a/slides/progfun1-1-1.pdf b/slides/progfun1-1-1.pdf deleted file mode 100644 index 98481344e094fe133de77685c0f61d094252f78e..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-1-1.pdf and /dev/null differ diff --git a/slides/progfun1-1-2.pdf b/slides/progfun1-1-2.pdf deleted file mode 100644 index 395946cdc8020ad3b92c4d99437ea9d895d8b7a8..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-1-2.pdf and /dev/null differ diff --git a/slides/progfun1-1-3.pdf b/slides/progfun1-1-3.pdf deleted file mode 100644 index cd34473e03d7d45ecbdf559e70167d03eedad35b..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-1-3.pdf and /dev/null differ diff --git a/slides/progfun1-1-4.pdf b/slides/progfun1-1-4.pdf deleted file mode 100644 index 1cc8c63808e1c95a120269df670309ce735c8f2c..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-1-4.pdf and /dev/null differ diff --git a/slides/progfun1-1-5.pdf b/slides/progfun1-1-5.pdf deleted file mode 100644 index 3bb114312992fb584d92fda18398991ad93f3eed..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-1-5.pdf and /dev/null differ diff --git a/slides/progfun1-1-6.pdf b/slides/progfun1-1-6.pdf deleted file mode 100644 index 7eb20bc6653546233732affd5971a7f562426995..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-1-6.pdf and /dev/null differ diff --git a/slides/progfun1-1-7.pdf b/slides/progfun1-1-7.pdf deleted file mode 100644 index 4504698f5567c8d8182c714dc3417a56d42b6347..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-1-7.pdf and /dev/null differ diff --git a/slides/progfun1-2-1.pdf b/slides/progfun1-2-1.pdf deleted file mode 100644 index a9b805473f9424664fe8ee574a72a6fda2cde231..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-2-1.pdf and /dev/null differ diff --git a/slides/progfun1-2-2.pdf b/slides/progfun1-2-2.pdf deleted file mode 100644 index d0c813c90862b3da520bfa08629e7135e13e7f4b..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-2-2.pdf and /dev/null differ diff --git a/slides/progfun1-2-3.pdf b/slides/progfun1-2-3.pdf deleted file mode 100644 index 1c0b3b88c21ef6934e20d4883d75db056f3f3cec..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-2-3.pdf and /dev/null differ diff --git a/slides/progfun1-2-4.pdf b/slides/progfun1-2-4.pdf deleted file mode 100644 index baeddc7e046d5c39fda22897de2a581ae1ebfa0d..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-2-4.pdf and /dev/null differ diff --git a/slides/progfun1-2-5.pdf b/slides/progfun1-2-5.pdf deleted file mode 100644 index 03ae403e71c4bdea1abd36de5e71e7d9189a2726..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-2-5.pdf and /dev/null differ diff --git a/slides/progfun1-2-6.pdf b/slides/progfun1-2-6.pdf deleted file mode 100644 index e29db28de87cdc8a519804788cc5688afae1849d..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-2-6.pdf and /dev/null differ diff --git a/slides/progfun1-2-7.pdf b/slides/progfun1-2-7.pdf deleted file mode 100644 index a1ce24776aadf7a9cde5173c123157b3d31702d7..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-2-7.pdf and /dev/null differ diff --git a/slides/progfun1-3-1.pdf b/slides/progfun1-3-1.pdf deleted file mode 100644 index c8f0670988280137ac4e241d6afeb379aad5ce76..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-3-1.pdf and /dev/null differ diff --git a/slides/progfun1-3-2.pdf b/slides/progfun1-3-2.pdf deleted file mode 100644 index d677bc47d5ce82bd390385bb418b51d1fdbb3548..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-3-2.pdf and /dev/null differ diff --git a/slides/progfun1-3-3.pdf b/slides/progfun1-3-3.pdf deleted file mode 100644 index 7b7b87e467add2a62fc7423687cbc07c09b4dcb7..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-3-3.pdf and /dev/null differ diff --git a/slides/progfun1-3-4.pdf b/slides/progfun1-3-4.pdf deleted file mode 100644 index a97b7dfa95d77761d406c8ddff790cbcda51459b..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-3-4.pdf and /dev/null differ diff --git a/slides/progfun1-3-5.pdf b/slides/progfun1-3-5.pdf deleted file mode 100644 index 2eeef74a0d032807735e235f8b71854b27a9b1de..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-3-5.pdf and /dev/null differ diff --git a/slides/progfun1-4-1.pdf b/slides/progfun1-4-1.pdf deleted file mode 100644 index f43750120d919459e4ed51a3efbdccd125ee9470..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-4-1.pdf and /dev/null differ diff --git a/slides/progfun1-4-2.pdf b/slides/progfun1-4-2.pdf deleted file mode 100644 index 797edafc2443991c539cf3c82fa397f5c2e43380..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-4-2.pdf and /dev/null differ diff --git a/slides/progfun1-4-3.pdf b/slides/progfun1-4-3.pdf deleted file mode 100644 index 5de94759c94d23bba91ae9b1d30221f1d76e5eea..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-4-3.pdf and /dev/null differ diff --git a/slides/progfun1-4-4.pdf b/slides/progfun1-4-4.pdf deleted file mode 100644 index 308fc36450fc62a278c5a61853bd4f1344124feb..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-4-4.pdf and /dev/null differ diff --git a/slides/progfun1-4-5.pdf b/slides/progfun1-4-5.pdf deleted file mode 100644 index 56ccbd0d6720258a1fd89b7e0a380e39217958ac..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-4-5.pdf and /dev/null differ diff --git a/slides/progfun1-4-6.pdf b/slides/progfun1-4-6.pdf deleted file mode 100644 index 4e241954decdbe8f8837844772b7332d8271a9ec..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-4-6.pdf and /dev/null differ diff --git a/slides/progfun1-5-1.pdf b/slides/progfun1-5-1.pdf deleted file mode 100644 index 15bc68535445981f89e7f0e72eaf15fefc2fb6e2..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-5-1.pdf and /dev/null differ diff --git a/slides/progfun1-5-2.pdf b/slides/progfun1-5-2.pdf deleted file mode 100644 index 8225a74e7a5a08ab3668177cfaa575dd6a8d8fcc..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-5-2.pdf and /dev/null differ diff --git a/slides/progfun1-5-3.pdf b/slides/progfun1-5-3.pdf deleted file mode 100644 index 43f724a66eb2122a4c67190d2b10bcf98f7579e8..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-5-3.pdf and /dev/null differ diff --git a/slides/progfun1-5-4.pdf b/slides/progfun1-5-4.pdf deleted file mode 100644 index e936acaab3a087ef1f56b5c6aa20e18d0a8f910c..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-5-4.pdf and /dev/null differ diff --git a/slides/progfun1-5-5.pdf b/slides/progfun1-5-5.pdf deleted file mode 100644 index aa52251fafaa854cb1e7eea12ad1919239de0b82..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-5-5.pdf and /dev/null differ diff --git a/slides/progfun1-5-6.pdf b/slides/progfun1-5-6.pdf deleted file mode 100644 index 1d5dff712b0fbc8fca4cb140f01253625e72e30b..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-5-6.pdf and /dev/null differ diff --git a/slides/progfun1-6-1.pdf b/slides/progfun1-6-1.pdf deleted file mode 100644 index 4bb31e78c6e73736542b4c361c636b06067de37c..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-6-1.pdf and /dev/null differ diff --git a/slides/progfun1-6-2.pdf b/slides/progfun1-6-2.pdf deleted file mode 100644 index 75774eae2aa9c4b887fbe7ba0c140b98b010d2ad..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-6-2.pdf and /dev/null differ diff --git a/slides/progfun1-6-3.pdf b/slides/progfun1-6-3.pdf deleted file mode 100644 index d89c42afcca8565db019b747e48e97f1629c68cb..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-6-3.pdf and /dev/null differ diff --git a/slides/progfun1-6-4.pdf b/slides/progfun1-6-4.pdf deleted file mode 100644 index cf228d6081cc669ad9ee9ab16213785bc12c7cad..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-6-4.pdf and /dev/null differ diff --git a/slides/progfun1-6-5.pdf b/slides/progfun1-6-5.pdf deleted file mode 100644 index 88a426a27c46384e17c3282145c61318244edfb9..0000000000000000000000000000000000000000 Binary files a/slides/progfun1-6-5.pdf and /dev/null differ diff --git a/slides/progfun2-1-1.pdf b/slides/progfun2-1-1.pdf deleted file mode 100644 index 47dd651f9180ae0e61d017d3ac5cefc168016edd..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-1-1.pdf and /dev/null differ diff --git a/slides/progfun2-1-2.pdf b/slides/progfun2-1-2.pdf deleted file mode 100644 index 3f02bea763edecbde0aadda2f92a5716f8e44a12..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-1-2.pdf and /dev/null differ diff --git a/slides/progfun2-1-3.pdf b/slides/progfun2-1-3.pdf deleted file mode 100644 index 501df96ed202ba9c6b3584400807d776a8722ecb..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-1-3.pdf and /dev/null differ diff --git a/slides/progfun2-1-4.pdf b/slides/progfun2-1-4.pdf deleted file mode 100644 index 8224577ce15a1ca885f300aa0e5b3724692f1873..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-1-4.pdf and /dev/null differ diff --git a/slides/progfun2-1-5.pdf b/slides/progfun2-1-5.pdf deleted file mode 100644 index 2f5a1b43c3ff28007a9745b392aa18d4a1086311..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-1-5.pdf and /dev/null differ diff --git a/slides/progfun2-1-6.pdf b/slides/progfun2-1-6.pdf deleted file mode 100644 index 34315477dffabaa34a263e5f422d96f6ac4f607d..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-1-6.pdf and /dev/null differ diff --git a/slides/progfun2-2-1.pdf b/slides/progfun2-2-1.pdf deleted file mode 100644 index af2e74fc1fb49e9aa0a272c99d3f0d4dde34d5a4..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-2-1.pdf and /dev/null differ diff --git a/slides/progfun2-2-2.pdf b/slides/progfun2-2-2.pdf deleted file mode 100644 index 85b264622533023003515da26de946dd7d6cdbf1..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-2-2.pdf and /dev/null differ diff --git a/slides/progfun2-2-3.pdf b/slides/progfun2-2-3.pdf deleted file mode 100644 index 6a37712d9dd4c7e3bf3dfd59902f3cc83dcb243b..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-2-3.pdf and /dev/null differ diff --git a/slides/progfun2-2-4.pdf b/slides/progfun2-2-4.pdf deleted file mode 100644 index eb169ed2effe51d7a1660d20e695b6a58c5f71f9..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-2-4.pdf and /dev/null differ diff --git a/slides/progfun2-2-5.pdf b/slides/progfun2-2-5.pdf deleted file mode 100644 index 8055c0b09987d4aa6082e3abed56d7413249411d..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-2-5.pdf and /dev/null differ diff --git a/slides/progfun2-3-1.pdf b/slides/progfun2-3-1.pdf deleted file mode 100644 index 9d3037725d8d89b039dcf30ab954fb0a2d736a82..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-3-1.pdf and /dev/null differ diff --git a/slides/progfun2-3-2.pdf b/slides/progfun2-3-2.pdf deleted file mode 100644 index 8d0409398e6bd1b55a1365aa6cb0a7bec42cc4aa..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-3-2.pdf and /dev/null differ diff --git a/slides/progfun2-3-3.pdf b/slides/progfun2-3-3.pdf deleted file mode 100644 index d760ea2ba150cc0943ad8dd4f6318268f251506a..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-3-3.pdf and /dev/null differ diff --git a/slides/progfun2-3-4.pdf b/slides/progfun2-3-4.pdf deleted file mode 100644 index a9c2ab61a8c7bcbbccfc731938575c60fd9d635a..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-3-4.pdf and /dev/null differ diff --git a/slides/progfun2-3-5.pdf b/slides/progfun2-3-5.pdf deleted file mode 100644 index 4659d28e61e163a99b07877a08a92d2f61b86e84..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-3-5.pdf and /dev/null differ diff --git a/slides/progfun2-3-6.pdf b/slides/progfun2-3-6.pdf deleted file mode 100644 index 98f1ebe11b2ddee3a142d22012462219bc952202..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-3-6.pdf and /dev/null differ diff --git a/slides/progfun2-4-1.pdf b/slides/progfun2-4-1.pdf deleted file mode 100644 index a0a24d91135d74d7548318ef6f75b5f89973d7db..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-4-1.pdf and /dev/null differ diff --git a/slides/progfun2-4-2.pdf b/slides/progfun2-4-2.pdf deleted file mode 100644 index 9bd9be6e6f7048353c7618b202db62d45eca4001..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-4-2.pdf and /dev/null differ diff --git a/slides/progfun2-4-3.pdf b/slides/progfun2-4-3.pdf deleted file mode 100644 index c459d069979ffbcbe91fff7cf5b222e6182571d3..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-4-3.pdf and /dev/null differ diff --git a/slides/progfun2-4-4.pdf b/slides/progfun2-4-4.pdf deleted file mode 100644 index 6b16e3e088c2f0abcaaf2b10c99c64e960c4351f..0000000000000000000000000000000000000000 Binary files a/slides/progfun2-4-4.pdf and /dev/null differ diff --git a/slides/progfun3-1-1.pdf b/slides/progfun3-1-1.pdf deleted file mode 100644 index 71428c2b6fb704ec44556fb93cd813eeff101e35..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-1-1.pdf and /dev/null differ diff --git a/slides/progfun3-1-2.pdf b/slides/progfun3-1-2.pdf deleted file mode 100644 index aa1682ed12d57b66cba91cb561d7b0ea24c88ced..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-1-2.pdf and /dev/null differ diff --git a/slides/progfun3-1-3.pdf b/slides/progfun3-1-3.pdf deleted file mode 100644 index a0e6db3b4c58878336dc1f1491295588647e3a17..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-1-3.pdf and /dev/null differ diff --git a/slides/progfun3-1-4.pdf b/slides/progfun3-1-4.pdf deleted file mode 100644 index d021448df01e29f902d647d20dfd5047d6104f7b..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-1-4.pdf and /dev/null differ diff --git a/slides/progfun3-1-5.pdf b/slides/progfun3-1-5.pdf deleted file mode 100644 index d2748d660c8ebe9be69fb9e24c51ff1b263bb51b..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-1-5.pdf and /dev/null differ diff --git a/slides/progfun3-1-6.pdf b/slides/progfun3-1-6.pdf deleted file mode 100644 index ac542185ff9cebb4f7724d425a96be6b8cc0c3b4..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-1-6.pdf and /dev/null differ diff --git a/slides/progfun3-1-7.pdf b/slides/progfun3-1-7.pdf deleted file mode 100644 index 217b170a60fc93958ee8e564914b0dba1c697b24..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-1-7.pdf and /dev/null differ diff --git a/slides/progfun3-2-1.pdf b/slides/progfun3-2-1.pdf deleted file mode 100644 index 30e6231a709e6e08170f5aa880e3717a7e3b6f67..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-2-1.pdf and /dev/null differ diff --git a/slides/progfun3-2-2.pdf b/slides/progfun3-2-2.pdf deleted file mode 100644 index 673db1dc9f4e7b9e158545de2c8befa1977fed98..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-2-2.pdf and /dev/null differ diff --git a/slides/progfun3-2-3.pdf b/slides/progfun3-2-3.pdf deleted file mode 100644 index 652eab8f66dd3b3929781d17e28d00e484bae3a1..0000000000000000000000000000000000000000 Binary files a/slides/progfun3-2-3.pdf and /dev/null differ