---
# System prepended metadata

title: Homework 2
tags: [Homeworks-F25]

---

---
tags: Homeworks-S25, 2025
title: Homework 2
---


# Homework 2: Ads Take Aim

### Due: Monday, September 22nd at 11:59 pm


![](https://imgs.xkcd.com/comics/mobile_marketing.png)

## Setup
- Create a new file named `hw2-code.arr` in [Pyret](https://code.pyret.org).
- Unlike with Homework 1, we are writing where-examples (test cases) for this assignment! Write examples for each function you implement using a `where` block. Here's an example:
```
fun add-one(n :: Number) -> Number:
  doc: ```Function adds one to the input number```
  n + 1
where:
  add-one(1) is 2
  add-one(3) is 4
  add-one(-1) is 0
end
```
- Write examples before you write your code! This will ensure you understand the question (and this habit will help you significantly later on).
- You will be graded on having examples that cover a variety of situations, so take a look at the [Testing and Style Guidelines](https://hackmd.io/@cs111/pyret-design-clarity-guide).
- **Do *not* put your name anywhere in any file.** We grade anonymously, and submitting online helps us keep track of your submissions without your names on the file!

## Helpful Things

### Documentation

The [Pyret documentation](https://www.pyret.org/docs/latest/) is accessible from the pirate icon on the top left corner of code.pyret.org.

For this assignment, you will find the [Strings documentation](https://www.pyret.org/docs/latest/strings.html) useful. We recommend briefly browsing through the documentation before working on these problems to get a sense of what functions are available! But don't worry about reading the page in detail – you can always come back for more information on a function you need.

### Getting Help If You Need It

You can post small questions on [Edstem](https://edstem.org/us/courses/84795/). Check the HW2 FAQ that will be pinned on Edstem first, as some questions may have already been asked and answered. *Make sure you're following our guidelines for Edstem, including not posting any solution code (or anything close to it) publically.*

If you have a longer question or want to go over something with a friendly staff member, come to [office hours](https://brown-csci0111.github.io/pages/calendar).

### Collaboration Policy

Starting with this homework, you are required to work on most assignments **on your own** and to make sure that the work you turn in is your own. If you are unsure of what this means, refer to the [syllabus](https://hackmd.io/@cs111/syllabus-f25#Collaboration-Policy) or ask! According to the official Brown policy on academic dishonesty, ignorance of a course's collaboration policy is not an excuse for plagiarism.

### How You'll Be Graded

Just as the syllabus lays out, having "working code" is only one means of demonstrating understanding of course concepts. You will be graded on a rubric that encompasses the following:

* The code passes *our* examples/tests (this is done by autograding, which is explained in a pinned post on [Edstem](https://edstem.org/us/courses/84795/))
* The functions you write have examples/tests written by you
* Your code follows our [Style Guide for testing, design, and clarity](https://hackmd.io/@cs111/pyret-design-clarity-guide)
* Your reflections are complete and thoughtful
* You show understanding of the specific learning goals of the assignment (for example, reusing functions you have previously written where possible in this assignment)

Make sure you follow directions. For example, for Task 1, make sure to write down 6-8 elements *and* put stars by some of them.

For this homework, we are only using what we've seen in class so far, and what you can find in the Pyret documentation on Strings, Numbers, and Booleans. Your approaches should **not** use Tables or Lists.

## The Big Picture of this Assignment

Targeted advertising is a real-world example of how data, computation, and social impacts come together. We want you to develop an understanding of how these systems work. This week, we start with the simplest form of matching ads: writing explicit conditional expressions to see whether a person is in the target audience for a single, fixed ad.

## The Assignment
Pilots often have to decipher the ads that they come across to see if there is any information on new jets or airline job openings. In this assignment, we are going to help our pilots by learning how to build functions that determine ad targeting.

![istockphoto-1685032752-170x170](https://hackmd.io/_uploads/BJ7z6I19gl.jpg)


*Image Source: [iStock Photo](https://www.istockphoto.com/vector/cow-graze-gm133971699-10745938)*

## Part 1: Representing Ads

The first step in processing something with a program is to *represent* that thing in terms of focused, discrete pieces of data. Consider the following ad for an outdoor adventure meetup:

 ![](https://i.imgur.com/sCzJgjD.png)


**Task 1:** Imagine that this ad was posted around town. Write down a list of 6-8 elements that are in this ad that are designed to attract people to it. 

Then, **put stars** (***) next to those elements that you think a program might use to decide whether to show the ad to someone.

Write your answer as a block comment in your code file. It should look something like the following (but in terms of ads, not calendars):

```
#|
My calendar includes dedicated times for
- looking for bears
- sleeping ***
- going to class ***
- exploring Rhode Island
|#
```

**Task 2:**
![this-ad-thinks-it-knows-you](https://i.imgur.com/0HCbaPc.png)
Data plays a big role in your life whether you are aware of it or not. For example, the information that a search engine has on you comes from a combination of your profile and predictions that the search engine makes about you.

Look at some of the information that Google gathers and infers about users. You can check out your own data by visiting https://myadcenter.google.com/ or look at the picture below for an example.

![ad-personalization information](https://i.imgur.com/h8E3t3U.png)

In a multi-line comment, answer the following questions:

1.  Using your data gathered by Google, *only if you’re comfortable*, what is the most surprising thing about your targeted ads?
    * If you don't have your Google personalized ads turned on or aren't comfortable with using your own data, you may skip this question. Remember to answer question 2!
2.  In **2-3 sentences**, discuss how Google may have come to infer these things about you and how this information might be used when making ad targeting decisions. 
    * If you don't have your Google personalized ads turned on or aren't comfortable with using your own data, use the information on the rightmost phone screen in the image above to answer this question.

**Note:** A summary of the examples submitted in this task may be shared after submission and grading. This may include paraphrased versions of your response. Everything will remain anonymous. **If you do *NOT* wish to share your response in any capacity, please write “DO NOT SHARE” at the beginning of the document.**

**Task 3:** For this assignment, we will use three pieces of information to represent an ad: the age of person it targets, the location of the event, and the kinds of activities it involves. Because we are working with a single fixed ad this week, we will store the information about the ad in three constants (values that we will access in the expressions that we write, using their names):

```
TARGET-AGE = 40
TARGET-TOWN = "Rockville"
TARGET-HOBBIES = "running, biking, walking, swimming, water polo"
```

Copy and paste these constants into the top of your code.

## Part 2: Writing Expressions

We're going to practice writing **expressions** (not functions, we'll get to those later in the assignment). It might seem a little strange to write down an expression when you could also just see what the answer is, but we are starting with these warmup tasks in order to transition to reasoning about functions in the later tasks. Think of this task as writing out a full mathematical expression in place of an answer, like `2 * 2` instead of `4`, but with programming! The expressions should refer to the names above (`TARGET-TOWN`, `TARGET-AGE`, `TARGET-HOBBIES`) instead of using their values (do not directly use the number `40`, the string`"Rockville"` etc).

:::spoiler An example of what we're looking for
If a task said *write an expression to determine whether Jeremy (age 22) is the `TARGET-AGE`, you would write

```
22 == TARGET-AGE
```
:::

When you hit "Run" and your expressions are evaluated, they might print out in the interactions window on the right-hand side of the screen. That's fine (for this assignment). If you want to stop this from happening, you can give the expression a name (e.g., `task1 = ...`).

**Task 4:** Write an expression to that evaluates to true if and only if Vanessa (age 21) is within 5 years (inclusive) of the constant `TARGET-AGE`.

*Hint: You can use the `>` and `<` symbols to compare two values with exclusive bounds (think "greater than") and `>=` and `<=` symbols to compare two values with inclusive bounds (think "greater than or equal to"). You might have to combine two comparisons with a Boolean operator (such as `and` or `or`).*

**Task 5:** Write an expression that evaluates to true if either `"Providence"` is *exactly* the same as `TARGET-TOWN` or `"reading"` is *exactly* the same as `TARGET-HOBBIES`.

*Note:* You can you use `==` or `string-equal` to do the comparison (the former works on any type of data, the latter works only on strings). For this homework, we are concerned only with exact matches (for example, we will treat "providence" and "Providence" as different strings).

**Task 6:** This time, instead of producing a Boolean, we want to produce  a String that indicates whether the target town, target hobbies, both, or neither *exactly* match `"Rockville"` and `"reading"` respectively (evaluating to either `"town"`, `"hobbies"`, `"both"`, or `"neither"`). Use nested `if` expressions (where one `if` is within the answer of the other) to write an expression that evaluates to the appropriate string.

*Hint: Remember that* `if` *expressions finish with* `end`.

:::spoiler More Detailed Explanation
*  If the target town matches `"Rockville"` but the target hobbies do not match `"reading"`, your expression should produce `"town"`.
*  If the target town does not match `"Rockville"` but the target hobbies match `"reading"`, your expression should produce `"hobbies"`.
*  If both match, your expression should produce `"both"`.
*  If neither match, your expression should produce `"neither"`.
:::
<br>

**Task 7:** Contrast the expressions for the previous two tasks (the one that returned the `Boolean` and the one that returned a `String`). Write 1-2 sentences in a comment comparing boolean logic and nested `if` expressions. When can we use each form? When must we use each form?

*Note: You can create multi-line comments when you go over 80 characters on one line as follows:*

```
# This is a regular comment.

#| This is a
   multi-line
   comment! 
|#
```

## Part 3: Writing Functions for Targeted Ads

So far, our expressions have used fixed information about a person to compare to the constants that describe the ad. Now, we want to check whether the ad is suitable for an arbitrary person. To do this, we need to write functions that take information about the person as inputs.

:::warning
**Note:** Remember to include type annotations, doc-strings, and examples with all of your functions! Refer to the [Style Guide](https://hackmd.io/@cs111/pyret-design-clarity-guide) if you need help with this.
:::

**Task 8:** Convert your expression from Task 4 (checking the age) into a function called `within-5`. This function should take in a `Number` representing a person's age and produce a `Boolean`. It should return `true` if `TARGET-AGE` is within five years of the input age (inclusive), and `false` if not. Make sure to write type annotations, a docstring, and examples.

*Note: For this task and the next few tasks, you should be able to re-use a lot of the logic from tasks 4-6. Think about the examples from class: what specific value from the expression can you replace with an input name to make the computation work on any input value?*

**Task 9:** Previously, our expressions checked for an *exact* match of a hobbies string to `TARGET-HOBBIES`. In practice, we might want to match an ad if a given hobby was *within* the string (what we call a "substring"), rather than an exact match. For instance, if our `TARGET-HOBBIES` is `"running, biking, walking, swimming, water polo"`, we might want to return a match if our input hobby string is `"walking"`.

Write a function called `hobby-relates`, which takes in a `String` representing a person's hobby and produces a `Boolean` which is `true` when `TARGET-HOBBIES` *contains* the input hobby string, and `false` otherwise. Take a look at Pyret's [Strings documentation](https://www.pyret.org/docs/latest/strings.html)  for an operation on strings that would help you do this (practicing using documentation is a key goal of this question, and is an important skill to develop in general).

**Task 10:** Consider someone who has hobbies that include `"mountain biking"`, `"polo"`, and `"swiming"` (which they misspelled by accident). Try out `hobby-relates` on each of these inputs (e.g. type the expression `hobby-relates("mountain biking")`, etc in the right side of the Pyret window and observe the result. In your code file under `hobby-relates`, write a multi-line comment about why each of these hobbies might lead to a misleading output from `hobby-relates`. 

**Task 11:** Our current approach to matching towns/locations for ads is a bit restrictive: someone who lives in a neighboring town might still be able to get there, and we'd like to target them as well. This motivates our next function.

Write the function `is-nearby`, which takes in a `String` representing the name of a town and produces a `Boolean`. Produce `true` if the input is *exactly* one of `"Forest Dale"`, `"Waterville"`, `"Newtown"`, or `"Oldport"`; produce `false` otherwise. 
    
**Task 12:** Now, let's practice calling functions in the body of another function. Write the function `in-range`, which takes in a`String` representing a person's town and a `Boolean` representing whether the person has a car. Produce `true` if the place is `TARGET-TOWN` *or* both the input place is nearby (one of the 4 towns in Task 11) and the person has a car. Otherwise, the function should produce `false`. 

**Task 13:** Now, it's time to put all the criteria together to determine whether an ad should be shown to a potential customer or not. Write a function called `show-ad`. The inputs are (in this specific order) a `Number` representing a customer's age, a `String` representing their town, a `String` representing their hobby, and a `Boolean` representing whether they have a car. The output is a `Boolean` which is `true` when their age is within five years of the target age (inclusive), their town is `TARGET-TOWN` or they are nearby and have a ca,, and `TARGET-HOBBIES` contains their hobby. The output is `false` otherwise.

**Hint:** Try to reuse your work from earlier tasks on this assignment (that's part of the point of this sequence of tasks).

### A Different Representation for Ads

So far, we have represented an ad as three constants (`TARGET-AGE`, etc). What if we represented each ad as a single string with all of its text instead? What other ways of matching people and ads might we try?

**Task 14:** Write the function `show-ad2`, which takes in a `String` representing the text of an ad and a `Number` representing a person's age, and produces a `Boolean`. This `Boolean` will be `true` if **any** of the following conditions are met, and `false` otherwise:

- The customer's age is 35 or younger and the ad contains the word "active"
- The customer's age is 65 or older and the ad contains the word "healthy"
- The ad contains the word "sport"

**Task 15:** Task 10 includes a real world example that shows how functions can produce unexpected or incorrect outcomes for certain individuals/groups. However, even when a function itself is "perfectly accurate" and does exactly what it's supposed to do, it can be *used* in harmful ways that we will continue to explore throughout the course. The function `show-ad2` makes assumptions about the customers that these ads are targeting. In a multi-line comment under `show-ad2`, list out at least two of these assumptions (consider the relationship between age and health, and what the criteria might be leaving out).

### Comparing different targeting methods

The functions `show-ad` and `show-ad2` are our first attempt at writing functions to match ads to people. We will revisit this theme as we learn more programming concepts, and our functions will become more sophisticated. 

**Task 16**: Write a multi-line comment (in your code file) responding to these questions about the approaches taken in these two functions:
- How might these functions differ from how real ads work? 
- Think about the way we set up the code and the programming operations that we used. What are the limitations of our current code/operations for matching ads with people? How might the ways that you processed data in this homework differ from how real-world data is stored and processed? (You don't have to know or research how this is done, but you should make an educated guess.)

**Task 17:** In a `check` block (just like a `where` block but not attached to any particular function), write **one** example for each ad-placing method (`show-ad` and `show-ad2`). This means that you should have a total of **two** examples, one for `show-ad` and one for `show-ad2`.

Each example should show a situation in which the function would output ``'false'`` (because of a limitation of the function), even though the ad would otherwise seem a good match for the person. Leave a short comment under each example explaining why you chose it.

Your `check` block should look like:
```
check "show-ad tests":
  show-ad(...) is false
  # Explanation
  show-ad2(...) is false
  # Explanation
end
```

## Part 4: Writing comprehensive examples

In this part, we're not going to write any code. Instead, we're going to thoroughly test a piece of code that someone else wrote.There are lots of ways companies might be collecting information from you. When you order something online, you provide your own personal information (such as an email address and phone number) that might then be used to communicate with you about other products. When you fill out such a form, a program detects whether the data you provided is in a valid format. Imagine that you want to hire a programmer to write a function called `is-phone-num` that checks if a given string is a valid phone number. For the purposes of this problem, a valid phone number is of the format `XXX-XXX-XXXX`, where each `X` is a numerical digit.

Your job is to write a `check` block for `is-phone-num`. It will look like the following (though you don't need to include our tests):

```
check "Basic tests for is-phone-num":
  is-phone-num("123-456-7890") is true
  is-phone-num("1") is false
end
```

**You are NOT writing the is-phone-num function itself**. The CS111 staff have already done that. In fact, we've written *several* versions, some that return the answers that you want and some that don't (think of these as proposed solutions from multiple programmers). We are going to grade your `check` block by running it against all of our versions and seeing whether your tests are comprehensive enough to tell the ones that work from the ones that don't.

:::spoiler How do tests tell apart working and non-working solutions?
Imagine that someone claims to have written a program `double` that doubles a number. You write a test
```
check:
  double(2) is 4
end
```
This will return true on both of the following functions:

```
fun double(x :: Number) -> x * 2 end  # a correct version
fun double(x :: Number) -> x + 2 end  # an incorrect version
```

Thus, a `check` block with only this one test isn't very good, because it doesn't have enough tests to flag that the second version doesn't work. If instead, you wrote the following tests:

```
check:
  double(2) is 4
  double(3) is 6
end
```
Now the first function passes both tests while the second function fails one of the tests. This is a more comprehensive test suite because has enough cases to catch errors in the functions. Your job on this assignment will be to figure out a set of tests that catch errors in as many of our broken solutions as you can.
:::
<br>

To run your tests against our many versions, you'll work in a custom version of Pyret. Click [this link](https://pyret.cs.brown.edu/assignment/1E5R9TD_uGVjvbKPu5rugp1teLuZmzc2b) to access the custom Pyret version. It might take some time to load (sometimes even 1-2 minutes), especially the first time. **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>

:::spoiler Did you accidentally click "begin implementation?"
Go to drive.google.com, logged in with the account you use for Pyret. Find the folder that is called "pyret.cs.brown.edu" (***not code.pyret.org***), and delete the file called "is-phone-code.arr". Refresh the examplar page and you should be good to go! ***Do not delete hw3-tests-examples.arr, since that contains your work!!!***
:::
<br>

**Task 18:** Fill in the `check` block that you see in the custom Pyret window. Your block should contain multiple tests for `is-phone-num`. 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. Pyret is running your tests against seven versions of `is-phone-num`, only one of which is correct (each of the other six is broken in some way). Your goal is to knock out as many of the six broken ones as you can.

*Note: 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. You will get full credit for catching four.* The output you are looking for is: (**don't worry about the "X tests failed" message**. This message would only be relevant if we asked you to write your own version of `is-phon-num`, which we're not. We just care about the output that says how many buggies you caught.)

![Screenshot 2025-09-11 at 5.34.36 PM](https://hackmd.io/_uploads/S1pUbTgilx.png)

:::spoiler Hints on how to approach this

The key to doing well on this is to think systematically about the conditions of the problem and the possible variations in the strings. It will help to have some examples of correctly formatted phone numbers, but also make sure you have plenty of examples with *incorrectly* formatted phone numbers that should result in `false`. What might an incorrectly formatted phone number be? Think about the assumptions of the format -- for example, the length of the input string, the kind of character that exists at every spot in the string, etc.
:::
<br>

**Task 19:** In your tests file, include a multi-line comment summarizing your strategy and what you learned about writing tests from doing this exercise. 

Download your tests file (you'll upload it with the code file when you are done with the assignment).

:::warning
If your tests download as a .zip file, unzip it to retrieve the Pyret file. Make sure your file is called `hw2-tests-examples.arr`. This will be submitted along with the `hw2-code.arr` file (from the other parts of this assignment) to Gradescope. If you also see a downloaded file called `hw2-code-ignore.arr`, disregard that file.
:::

## Part 5: Cleaning up code

In this exercise, we want you to use three concepts we've learned---local names, helper functions, and examples---to make a piece of code easier to read without changing what it computes.

**Task 20:** In `hw2-code.arr`, copy the following function, which computes the cost of publishing an ad based on the length of the ad text. Rewrite it into a new version called `ad-charge-clean` that meets the Design and Clarity requirements of the [Style Guide](https://hackmd.io/@cs111/pyret-design-clarity-guide). 

```
fun ad-charge-messy(ad-text):
  short-length = 10
  medium-length = 40
  long-length = 70
  if ((string-length(ad-text) >= short-length) and (string-length(ad-text) < medium-length)):
    (string-length(ad-text) * (short-length / 2)) + (string-length(ad-text) * 5)
  else if ((string-length(ad-text) >= medium-length) and (string-length(ad-text) < long-length)):
    (string-length(ad-text) * (medium-length / 2)) + (string-length(ad-text) * 5)
  else if (string-length(ad-text) >= long-length) :
    (string-length(ad-text) * (long-length / 2)) + (string-length(ad-text) * 5)
  else: 0
  end
where:
  ad-charge-messy("Go Bruno!") is 0
  ad-charge-messy("Apply to Brown") is 140
end
```

*Hint:* Part of the point of this exercise is to figure out what the code is doing. You can either copy the code and edit it to clean up or try writing parts from scratch: follow whichever makes the most sense to you. Try looking for repeated or similar expressions: repeated expressions turn into locally-named ones, while similar expressions get turned into helper functions.

**Task 21:** We want to make sure that the clean version produces the same output as the original messy one. Provide a `check` block of the following form to convince yourself that your two versions are consistent in their outputs:

```
check:
  ad-charge-messy("Go Bruno!") is ad-charge-clean("Go Bruno!")
  ...
end
```

## Check Block (Autograder Compatibility)
When you have completed all the tasks of this homework, please copy the following check block into the bottom of your code file! Then, hit "Run".

The check block will be checking that all required functions are included, correctly named, and that they handle inputs in the right order. Please note that it does **not** check or confirm if the body of your function is correct – you should write your own examples to convince yourself of this.

```
check "functions exist and have correct inputs":
  within-5(0)
  hobby-relates("")
  is-nearby("")
  in-range("", true)
  show-ad(0, "", "", true)
  show-ad2("", 0)
  ad-charge-messy("Go Bruno!") is ad-charge-clean("Go Bruno!")
end
```

If you see the block below appear in the interactions window after running it, then you're good to submit the code!

![](https://i.imgur.com/vp6aMHK.png)

If not, double-check your function names, input types, and input order. If you are stuck at any point, please feel free to come to hours or post on [Ed](https://edstem.org/us/courses/84795/)!

Once the check block passes, please submit your code file to [Gradescope](https://www.gradescope.com/courses/1103553). To help you, we have made some of our autograder tests on Gradescope visible to you – wait a while for the autograder to finish running, and check Gradescope to make sure you also pass those tests! The tests on Gradescope check for *correctness*, but all visible tests passing *may not* mean that your function is fully correct. See the post on [Ed](https://edstem.org/us/courses/84795/) about the autograder for more information!

-------------

## Handin
- Make sure your code file is called `hw2-code.arr`. Download both your code file and your test file (from part 4) and make sure they are called `hw2-code.arr` and `hw2-tests-examples.arr` respectively. Hand both in into the HW2 assignment on [Gradescope](https://www.gradescope.com/courses/1103553) *in the same submission*. Because we only see the latest submission, **make sure that you submit both files in the same submission when you are done**.
- You may submit as many times as you want before the deadline. Only your latest submission will be graded (though you will spend late days if the latest submission is after the due date).


## Theme Song
[Fly Me To The Moon](https://www.youtube.com/watch?v=ZEcqHA7dbwM&list=RDZEcqHA7dbwM&start_radio=1) by Frank Sinatra.

## Spotify Playlist
<iframe data-testid="embed-iframe" style="border-radius:12px" src="https://open.spotify.com/embed/playlist/6HiBE5A4YvHZHC5jwxZYoe?utm_source=generator" width="100%" height="352" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>
------

> Brown University CSCI 0111 (Spring 2025)

<iframe src="https://forms.gle/avVrN7H8u6hjiH8j7" width="640" height="372" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe>