--- title: Homework 3 tags: Homeworks-F21, 2021 --- # Homework 3: Row, Row, Row **Due:** Tuesday, September 28, 2021 at 9:00PM ET. ## Setup and Handin ### Setup - **Task:** Create a file in [Pyret](http://code.pyret.org) called `hw3-code.arr`. You will write your solution in here. You will need to copy and paste the following at the top of the file. ``` provide * provide-types * include shared-gdrive("dcic-2021", "1wyQZj_L0qqV9Ekgr9au6RX2iqt2Ga8Ep") include tables ``` - You will be graded on the quality of your tests for each function. :::spoiler What does this mean? - High-quality tests cover the simple/basic cases for each parameter, values at/around any boundaries mentioned in the problem statement, common cases, and potentially subtle cases (e.g., strings with two uses of a character where a function is looking for one use). - You do not need to include tests for erroneous inputs (such as negative numbers if only positives make sense for the problem). ::: - Do **not** put your name anywhere in the file. ### Handin - Download both your solutions file and your test file (instructions about creating the test file are in Part 2) and make sure they are called `hw3-code.arr` and `hw3-tests-examples.arr` respectively. Hand in your work on [Gradescope](https://www.gradescope.com/courses/302007). ### Remember your resources! - [Pyret documentation](https://www.pyret.org/docs/latest/) - [CS0111 Table documentation](https://hackmd.io/@cs111/table) (use this **instead** of the official `Table` documentation) - [Strings documentation](https://www.pyret.org/docs/latest/strings.html) (particularly applicable for this assignment) - [Edstem](https://edstem.org/us/courses/12806/discussion/), and particularly our [Homework 3 FAQ post](https://edstem.org/us/courses/12806/discussion/583849) - [Course syllabus](https://hackmd.io/@cs111/syllabus-f21) - [Code clarity guide](https://cs.brown.edu/courses/csci0111/fall2021/assets/docs/pyret-clarity-design-testing.html) - Style tip: ALL lines (including comments) must be under 100 characters long :::spoiler Useful Functions - `not` is a builtin function that takes a Boolean, and inverts it: `not(true)` &rarr; `false` and `not(false)` &rarr; `true` - `==` is an equality test; `3 == 3` &rarr; `true` and `3 == 4` &rarr; `false`. ::: ## The Assignment ## Part 1: Nicknames :::info Learning Goals: - To practice writing functions using string functions and boolean operators - To practice using documentation to find useful built-in functions ::: Annie, Erick, Ashley, and Ryan decide to give each other nicknames. Each nickname is formatted as a `String` in a specific way by pairing a real name and a nickname with diamond brackets and a comma. There are some strict conditions for which nicknames are allowed! <!--- Julia: I removed all the examples of what's valid/invalid because we had a lot of students copy and paste these into their tests -- I saved the old version in case we want to revert back but I feel like the descriptions themselves are sufficient to understand the criteria. ---> Requirements for a valid nickname pair String: - The first and last characters of the `String` must be `<` and `>` respectively :::spoiler *Hints* - *What characters (by position) of the `String` are we looking at? Which string library function can look at specific positions/characters in a `String`?* ::: - The `String` must have a comma as its middle character (with the same number of characters on either side) :::spoiler *Hints* - *What does this tell us about the length of the string? Can it be even? Here's a function to check if a number is odd or not, but you don't need to use it.* ``` fun is-odd(n :: Number) -> Boolean: doc: "Checks if a number is odd" not(num-modulo(n, 2) == 0) end ``` - *How can we check that the middle character (by position) is a comma? Start by finding the index of the middle character.* - *The function num-floor() might be useful.* ::: - The name and/or nickname must contain the letter "a" somewhere in it (case sensitive) :::spoiler *Hints* - *Take a look at Homework 2 and see how you checked if a `String` was contained in another `String`.* ::: - The name or nickname CANNOT contain the sequence `"curse"` (case sensitive) (Annie, Erick, Ashley, and Ryan are very superstitious!) :::spoiler *Hints* - *Something like `"<acu,rse>"` would be valid because the comma interrupts the sequence, but something like `"<ashley,curser>"` would be invalid.* ::: **Task:** Write the function `nickname-check` in the file `hw3-code.arr`. `nickname-check` will take in a `String` (the name-nickname pair), and output a `Boolean` that indicates whether or not the input pair is allowed. Make sure to include a doc string, input/output type annotations, and a `where` block. *Note: Being able to look in language documentation for useful operations is an important skill, which is why we aren't telling you exactly which `String` operations to use. We want you to look at the `String` documentation to find useful operations for solving this problem. However, limit yourself to operations with input and output types that we have used this semester (`Number`, `String`, `Boolean`). Don't use operations that return `List`, as we haven't covered that yet.* ## Part 2: Practice Writing Comprehensive Tests :::info Learning Goal: - To practice developing a comprehensive set of tests for a function ::: After Homework 2, business is picking up, and Pedro is looking to expand his staff! He wants to purchase software to help him score resumes based on the candidate's current job title. There are several products available, and Pedro doesn't know which one to pick. He decides to create a collection of tests that describe the decisions he wants the software to make. He'll run his tests against the various tool options as a way to rule out products that don't suit his needs. You are going to help Pedro design a good set of tests that capture his goals. **You are NOT writing any functions for this part.** Pedro wants to give each product a string (consisting of a job title) and get back a number (representing a score of that title against Pedro's needs). - Scores are determined by words that appear in a job title. Here are the scores associated with the specific jobs that Pedro is tracking: (the higher the score, the better it matches his criteria) - 5 for “marketing”, 4 for “artist”, 3 for “media”, 2 for “writer”, and 1 for “editor” - Job titles with none of these terms score 0 - Capitalized keywords should be matches (e.g. "Marketing associate" matches), but the keyword should not be a part of another word (e.g. "editorial assistant" does not match) - If there are two (or more) keywords in the job title, output the score for the higher of the keywords Your job is to capture these goals in a set of tests, such as ``` resume-ranker("editor") is 1 ``` where `resume-ranker` is a function provided in the software product that Pedro is testing. We are providing a custom version of Pyret that has the code for the different software products. Pyret will run your tests against each of the products. **Task:** Click [this link](https://pyret.cs.brown.edu/assignment/1Cc8F8zfORvussnGdej_M0X2VVcsCkHWH) to access the custom Pyret version. **DO NOT click "Begin Implementation".** :::spoiler Pyret/Examplar not loading? Try removing permissions for Pyret@Brown from your Google account. You can do this by going to Manage your Google Account, searching "apps" in the search bar on top of the page, and removing permissions for Pyret@Brown. Then, revisit the link, log in, and re-allow permissions. If you have any questions, post in Ed or come to hours! ::: <br> **Task:** Fill in the `check` block with your tests (Reminder: you aren't writing `resume-ranker`, only tests). As you add tests and hit "Run", the report in the interactions window will show you how many unsatisfactory software products you've ruled out. :::spoiler What's going on here? We have seven different versions of that function behind the scenes (one from each competing software company). You are going to enter your tests in this custom version of Pyret that has access to the seven versions. This version of Pyret will give you a report indicating whether your tests express what Pedro wants, as well as how many of the versions you have ruled out. ::: :::spoiler What's the goal? Your goal is to eliminate as many of the products as you can. There is one product that satisfies all of Pedro's requirements. The other six are each off in some way. As your tests get more comprehensive, you'll knock out more of the unsatisfactory ones. ::: :::spoiler Do I need to knock out all of the unsatisfactory products? You don't have to knock out all of the unsatisfactory products to do well on this. This is our first exercise that focuses on designing good tests. This week, we're trying to build up your experience writing tests. Aim to knock out at least four, and see if you can get all the way to knocking out all six. ::: <br> **Task:** In your tests file, include a multi-line comment summarizing your strategy or what you learned about writing tests from doing this exercise. **Task:** Download your tests file. If it downloads as a .zip file, unzip it to retrieve the Pyret file. Make sure your file is called `hw3-tests-examples.arr`. This will be submitted along with `hw3-code.arr` to Gradescope. If you also see a downloaded file called `hw3-code-ignore.arr`, feel free to disregard this file. ## Part 3: More sophisticated ad matching :::info Learning Goals: - To give you practice accessing data from tables - To help you understand the benefit of bundling small pieces of data into one larger piece of data ::: In Homework 2, we wrote a `show-ad` function to help Pedro match ads to users. It had the following header: ``` fun show-ad(age :: Number, town :: String, hobby :: String, has-car :: Boolean) -> Boolean: doc: "figure out whether or not to show this customer the ad" ... end ``` In reality, ad-matching systems check dozens of pieces of information about users, not just four. Does that mean real ad systems have functions with 40-50 parameters? No! Instead, real ad systems bundle multiple pieces of information about a user together to make it easier to handle. This week, we look at tables to do that bundling. The information about one user would then be a **row** in the table. We want to update our `show-ad` function to work with individual rows, rather than separate pieces of information. Specifically, we want`show-ad` to look like: ``` fun show-ad(user-info :: Row) -> Boolean: ... end ``` where the `user-info` is a row from a table of user data which has columns for `age`, `town`, `hobby`, and `has-car`. ### Part 3A: Rewriting `show-ad` to use Rows :::danger *Note: It is **extremely** important that you make sure to use the [CS0111 Table documentation](https://hackmd.io/@cs111/table), not the official `Table` documentation. This includes the documentation for `Rows`, which is necessary for this assignment.* ::: *Note: To help you rewrite `show-ad`, we are providing our solutions to its helper functions from hwk 2. They are in a file called `hw3-helper.arr`, which is available in the Files area on Canvas. **Do not look at `hw3-helper.arr` before you turn in Homework 2.** We can tell when you look at something, and we'll be checking to see who peeks.* :::spoiler *How do I open `hw3-helper.arr`?* Download this file from Canvas. You can open it in a plain-text editor (e.g. TextEdit, WordPad) to copy and paste into your `hw3-code.arr` file. If you want to see it in Pyret, navigate to [code.pyret.org](https://code.pyret.org) and hit "View in Google Drive". Once You're in the Google Drive folder, drag and drop the file in, right click on it > Open with > Pyret. ::: <br> **Task:** Copy and paste the contents of `hw3-helper.arr` into your `hw3-code.arr` file below your answers for Part 1. The helper code contains the table `CUSTOMERS`: ``` CUSTOMERS = table: age :: Number, town :: String, hobby :: String, has-car :: Boolean row: 21, "oatman", "swimming", false row: 21, "kingman", "swimming", true row: 21, "kingman", "swimming", false row: 21, "providence", "swimming", true row: 18, "oatman", "swimming", true row: 21, "oatman", "reading", true end ``` **Task:** Using these global variables and helpers, write a new version of `show-ad` which takes in a `Row` and outputs a `Boolean`. You may assume that the input `Row` comes from the provided table (and thus has its column names). As a reminder, `show-ad` returns `true` when `within-5` and `hobby-relates` and `in-range` are all `true`; otherwise, it returns `false`. *Hint: To get a particular cell of a `Row`, use square bracket notation like this: `my-row["column-name"]`.* **Task:** Make sure to include tests for `show-ad` in a `where` block. To get an input `Row` to call `show-ad` on, you can get any `Row` from the global variable `CUSTOMERS` by using `row-n`. For example, `CUSTOMERS.row-n(0)` will give you: ![row example](http://cs.brown.edu/courses/csci0111/fall2020/data/hw3_example_row.png) **Clarified 9/27:** *Given that we haven't gotten to discuss this issue much in lecture yet, we will not grade the quality of your where block on hwk3. It is still a good idea for you to try to write one to get a sense of the structure, but you won't be graded on it. We'll come back to this in hwk4.* <!--- **Task:** We need to check whether `likes-coffee` matches the ad (i.e. if someone likes coffee and the ad wants coffee-drinkers). Should this be its own function or should you just check it directly in `show-ad`? What are the advantages/disadvantages of each? Write a comment below `show-ad` answering these questions. We're going to use helper functions for this. You can put them right under your helpers from `hw2-code.arr` and above your `show-add` function. **Task:** Write the `coffee-match` function, which takes in a `Boolean` and returns `true` if the user's coffee status matches that of the ad, `false` otherwise. Check whether the values for `likes-coffee` match. **Task:** Write the `check-phone-usage` function, which takes in a `String` representing the desired phone usage of an advertiser. The input `String` **must** be either "frequently", "sometimes", or "never". The function should return true if the user's phone usage is **at least** as frequent as the ad wants. :::spoiler Click for another explanation of `check-phone-usage`: For example, if the ad wants a phone usage of "sometimes", the function should return true if the input is "sometimes" or "frequently", and false if it is "never". If the input is not one of the three acceptable strings, simply return false. *Hint: If it helps, think about phone usage in terms of minutes. The minutes required by the ad must be less than or equal to the amount of time the user is on their phone.* ::: #### **Make sure** your `show-ad` function uses `coffee-match` and `check-phone-usage` along with other helper functions. ---> ### Part 3B: Excluding what the ad doesn't care about :::info Learning Goals: - To start to look at how to handle blank or missing data in tables ::: Sometimes, an ad company doesn't have the information for all of the cells for a given users. In this case, some cells of the table might be blank. For the purposes of this assignment, we consider a `String` to be blank if it is an empty string (which we write as `""`) and a `Number` to be blank if it is negative. **Task:** Modify the relevant helper functions (for `show-ad`) to handle blank values for the `hobby` and `age` columns. The challenge here is to figure out when and how to handle these blanks. You do not need to handle blank cases for anything besides `hobby` and `age`. Make sure to add relevant tests using blank values to the `where` blocks for any helper functions you edit and to `show-ad` to document this functionality. Since none of the rows in `CUSTOMERS` have blank values, you can add some rows to our definition of `CUSTOMERS` and access those with `row-n`. **Task:** Could you do something similar to using `""` for a blank `String` or a negative number for a blank `Number` in order to handle blank values for the column `has-car`? Why or why not? Are there other downsides to taking this approach? Write a comment under `show-ad` answering these questions. ## Part 4: What Your Car Won't Tell You ... :::info Learning Goals: - To learn about ways data are gathered about us beyond web browsing - To think about the implications of data tracking ::: Web browsers aren't the only kinds of tools that are gathering data about us. Data-enabled devices have access to a lot of data about us. What is getting collected, and what control might we have over this collection? **Task:** Read the article [“Your Car Knows When You Gain Weight”](https://www.nytimes.com/2019/05/20/opinion/car-repair-data-privacy.html) on how the objects we use are also collecting data on us, and who has the rights to use those data. (You can use [this guide to access the New York Times through a free academic pass](https://library-brown-edu.revproxy.brown.edu/eresources/nytimes.php) if needed.) **Task:** Go to [this separate gradescope assignment](https://www.gradescope.com/courses/302007/assignments/1514256) to answer several questions regarding this article. There is no right or wrong answer here. For this assignment, we are having you practice being concrete in talking about the context of computing technology and identifying potential impacts of data collected by objects around us. **Task**: Please add a comment at the bottom of your code file with the approximate number of hours you spent on this homework. This will be used only to average how long the homeworks are taking students this semester, and it is completely anonymous. Thank you for working to help us improve this class as we grow! ## Theme Song [Row Row Row Your Boat](https://www.youtube.com/watch?v=7otAJa3jui8) by Eliphalet Oram Lyte ------ > Brown University CSCI 0111 (Fall 2021) > Do you have feedback? Fill out [this form](https://forms.gle/Unux1ZBjUmxMqxPv8).