392 views
   owned this note
# Homework 4: Much Ado about Lists! **Due:** Friday, October 30th, 2026 at 11:59 PM. ### Setup - We are not using a stencil/helper code file for this homework! - Create a file in [Pyret](http://code.pyret.org) called `hw4-code.arr` where you will write your Homework 4 solution. - **[Change your context](https://cs111-docs.cs.brown.edu/s/table) to `dcic2024` (you'll need this for task 5)** - Do **not** put your name anywhere in the files. ### Remember your resources! - [Pyret documentation](https://www.pyret.org/docs/latest/) - [Pyret String Documentation](https://pyret.org/docs/latest/strings.html) - [Pyret List Documentation](https://pyret.org/docs/latest/lists.html) - [TA hours](https://brown-csci0111.github.io/pages/calendar.html) - [Edstem](https://edstem.org/us/courses/102199) ## The Big Picture of this Assignment This assignment has two goals: to give you some practice writing list functions, and to step back and give you a chance to show us what you have learned about writing clean code and developing a good set of examples for a problem. It's something of a mid-semester checkpoint on your program development skills. We'll be paying particular attention to your code organization and testing in grading this assignment. :::info Learning Goals - To practice writing recursive functions over lists - To practice using map and filter functions - To practice testing list programs ::: This assignment draws on some basic ideas about analyzing texts. For some of these problems, we will tell you whether to use the built-in list operations (like `map` and `filter`) or an explicit recursive function (written with cases and based on examples, like we've been doing in lecture). ## The Assignment Crystalline Cavan is a self-proclaimed bardolator. During his free time, he analyzes William Shakespeare's famous *Much Ado About Nothing*. In this homework, you will use your coding skills to help Crystalline Cavan perform this analysis. ![Two vintage William Shakespeare souvenir portrait pin dishes, atop a wooden table](https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTb9lNQo3yc5Sp1a4i-vH9YW2zqljmxQ7bRmA&s =400x) [Source](https://www.ebay.com/itm/174334746224) ## Part 1: Analyzing Literature Computational tools are helping literature scholars find patterns in text. With the text of many books now available online, we can download that text and use programs to extract data about the text. For this part of the assignment, we will work with the text of the play [Much Ado About Nothing](https://docs.google.com/document/d/1-Y8R3TjHm37mta9QFjoOBlrkysK19y5qajFCveTi8EY). Our goal is to determine the number of lines in the play that are spoken by each character. Specifically, we want to generate a table with two columns: the first column holds names of characters in the play and the second column holds how many lines that character had in the play. There should be only one row per character, but those rows can be in any order. **Unlike with earlier tables work, for this assignment we will be building Tables from Lists.** We'll introduce the operations that you need as they come up in this assignment. **Task 1:** Copy this code into your `hw4-code.arr` file. The text of the play is defined (in the `shakespeare-text.arr` file) as one long string named `book-text`. ``` include shared-gdrive("shakespeare-text.arr", "1-XGIpbC13ItjxCh7WY14cCjfygk5wz5x") ``` After including this line and running the file, take a look at what `book-text` evaluates to in the interactions pane. To examine the text, we have to convert the single `String` that contains the text to a List of words. **Task 2:** Create a list named `book-words` that contains all of the words in `book-text` in order. In other words, we are converting the single string for the text into a list of the words. You should be able to do this in a single line. Refer to the [Pyret String documentation](https://www.pyret.org/docs/latest/strings.html) if you don't remember the function that we've seen earlier in the semester that does this (professionals refer to documentation to look up functions they've used before all the time). ### Identifying the characters In order to build our table of lines per character, we first need to identify all of the characters in the play. Luckily for us, this play text used character names in ALL-CAPS to label each line (real text is usually messier). Thus, we need to isolate all of the ALL-CAPS names. Since this assignment practices different ways to process lists, we want you write this two ways: once using built-in list operations and once as a recursive function. **Task 3:** Write a function called `find-charactersB` that takes a list of `String` and returns a list of all of the *unique* character names in the given list. Your implementation should use built-in list operations and no manually-written recursion. You may write non-recursive helper functions (and call them with or without `lam`, as you prefer). **Task 4:** Now write a second version of this function called `find-charactersR` with the same inputs/outputs, but that uses recursion instead of built-ins. Your output list may contain duplicates (or not, that decision is up to you). **Note:** Remember how we wrote such functions in class: start by writing out the entire list pattern (with the cases and the call to the function on the rest of the list), then try to fill in the holes to finish the function. **Note:** We are not asking for sophisticated text processing here. We're asking you to find words in ALL-CAPS. Don't try to filter out for ALL-CAPS words that might not mark lines, etc. **Our tests assume that you've counted all ALL-CAPS words, plain and simple**. Yes, this includes "I", "O", and "A". **Testing:** You should have several `where` examples for each of these functions (you can use the same examples for both, as long as they're comprehensive). ### Creating a Table of lines per character Now that you have a list of all the names, it's time to create a table summarizing the number of lines per character. We are going to do this using functions over lists. In particular, **do NOT use the `count` or `build-column` functions in the table documentation** (there will be no credit for that solution). **Final table requirements:** the table produced for this part should have one row per character. It should have columns called `"name"` and `"line-count"`. The character rows can be in any order. To do this, we're going to create a list of the contents of each column in the desired table, then add those column-lists to the table. In class, we talked about how `map` creates a one-to-one correspondence between the input list and the output list (that is, the first element of the result corresponds to the transformation function being applied to the first element of the input, same for the second element of the result and input, and so on). This alignment will allow us to create our columns as separate lists that line up row-by-row when we put them in a Table. <details> <summary> More information on the concept </summary> <hr> Say we had a List of numbers `col1 = [list: -2, -1, 0, 1, 2]`. If we used `map` to square each number, ``` col2 = map(lam(x): x * x end, col1) ``` the result would be `[list: 4, 1, 0, 1, 4]`, that is, position-by-position, the values in `col2` are the squares of the values in `col1`. If we then "rotated" these Lists by turning them into columns of a Table in the order they appear, we would get | num | square | | --- | --- | | -2 | 4 | | -1 | 1 | | 0 | 0 | | 1 | 1 | | 2 | 4 | that is, each row contains a number and its corresponding square. This alignment is possible because `map` preserves the order of the input elements when applying a transformation. <hr> </details> <br> Here are functions that will help you do this: - `create-table-with-col :: (colname :: String, colvals :: List<Any>) -> Table` <BR> This function takes a column header (like `"name"`) and a list of values and creates a single-column table with those values. - `add-col :: (t :: Table, colname :: String, colvals :: List<Any>) -> Table`<br> This function takes a table and adds a new (rightmost) column with the given colname and values. The list of `colvals` must be the same length as the number of rows (without the header/column name.) Play around with these functions in the interactions pane to better understand how they work (remember, you'll need to change your context to `dcic2024` for this!). **Task 5:** Write a function `characters-table` that takes in a `String` with the text of a play and produces a Table summarizing the number of lines spoken by each character. Remember that character names in ALL-CAPS are used to label lines spoken by that character. You should not use `count` or `build-column` in this task. **For this task, all names in the output table should be **unique**.** Hints and notes: - You may use any combination of built-in operators and recursion to create the two lists being turned into columns - How can you use your code from previous tasks? - The discussion above talks about using `map` to create a one-to-one correspondence between the lists. What should the first input (transformation function) be? You'll probably have to write a helper function here - The output for an empty String (or input play with no characters in it) should be an empty Table, just like in the `check` block at the bottom of this handout. How can you build an empty table using `create-table-with-col` and `add-col`? This is your chance to show what you've learned about writing clean and robust code for a nontrivial problem! Sketch out a plan and thoroughly test any helper function(s) you've made before you begin. **Task 6:** Develop two good examples of shorter input strings to use to test your `characters-table` function (and use them in a `where` block for that function). Put a comment above each example indicating what situation(s) you designed it to help test. **Note:** You can define example output tables, or you can generate a character table then pull out individual cell values to check. This can make your testing much easier and less annoying to write. <details><summary><b>where-block example starter</b></summary> ``` where: output-char-tab = characters-table(my-input) output-char-tab.row-n(0)["name"] is ... output-char-tab.row-n(0)["line-count"] is ... ... end ``` </details> ## Part 2: Looking at Text in Context Our first text analysis centered around individual words. For some questions, however, we need to look at text in *context*, meaning that we consider the words that occur close to other words. This set of problems looks at how we write programs to consider words in context. Imagine that you are analyzing a text that features two characters named Gabriel (Gabriel Sun and Gabriel Costa). You want to see which one is mentioned more often. To do this, you need to inspect the words immedately *after* "Gabriel" in the text (which could be either one of the characters' last names or some other word). **Task 7:** Use [Examplar](https://pyret.cs.brown.edu/assignment/1NEwuc3YcoJZKf0RwIHUfJfQnsRWeRAzJ) to develop a comprehensive set of tests (in a `check` block) for a function named `count-a-gabriel`, which takes a `String` of main text (multiple words) and a `String` containing a last name to track and returns a `Number`. The function returns the number of times that the given last name directly follows `"Gabriel"` in the main text. Accept any capitalization of "gabriel" and the given last name. **To run the Examplar, press the Run button in the upper right hand corner. Do NOT press the "Begin Implementation" button, doing so will break your Examplar.** Refer back to the instructions in HW2 if you've done this. *Note: There are 8 broken solutions. Finding 7 will get you full credit (with proportional partial credit for finding fewer than 7).* **Designing a Solution:** Now it's time to think about how to implement `count-a-gabriel`. This is a different style problem than what you've done before, so let's think through how to approach it. As we've discussed in lecture, people program by retrieving/remembering solutions to problems that they've already seen and adapting them to a new situation. We have done problems that count list items before, but not problems that count *surrounding* items. We've seen two approaches to counting occurrences of items: (1) a combination of `filter` and `length` or (2) explicit recursion. <details> <summary> <b> Which makes sense here? Think about it before opening this to check your answer.</b> </summary> <i> The built-in functions, by design, only look at one element of a list at a time. In this problem, we need the surrounding words, so we have to use explicit recursion.</i> </details> <br> If you already see how to adapt a previous counting approach to write `count-a-gabriel`, jump down to Task 8. Otherwise, read on for guidance. Sometimes, we can successfully adapt code by actually writing out the original version and deciding how to modify it. Set aside checking the last names, and write down the previous approach that you know to just count appearances of `"Gabriel"` in the given string. (We're serious, type it into your file and make sure it works). Now, look at that code and identify what has to be different to count the word after `"Gabriel"` instead. Keep the high-level structure of the code that you have, and decide how you'll need to modify it. **Task 8:** Implement `count-a-gabriel` in your Pyret file. It should take in the same inputs as described in Task 7, and your code should pass the tests that you developed through Examplar. You are welcome to go back to Examplar and add more tests if something occurs to you while you are writing the function. :::info **Interpreting the autograder:** We have made *all* of our autograder tests for `count-a-gabriel` visible for you. Each test *roughly* corresponds to a situation you might have caught using examplar (we say "roughly" here because the tests you write may catch multiple chaffs, and because the order of the buggies as they appear in Examplar does not match the order of the autograder tests). We've done this so that you can decide when to stop working on this problem yourself -- if handling a specific edge case in your implementation is costing you a lot of time, you may choose to sacrifice those one or two autograder points (which will end up being a fraction of a percent of your final grade) and instead focus on your code style, other assignments, or your interests outside of school. ::: --- In this homework, you turned a piece of literature into data that the computer understands (in this case, a list of strings). This is very similar to what some data scientists do to create AI training data. Those training data are used to create generative AI models like ChatGPT, producing AI literature and art. You might have heard about AI art and the controversies surrounding it. For this assignment, we want you to consider a specific case study: AI music. *Note: to fully engage in the following questions requires around 20 minutes of your time. This might seem long! But hopefully some videos, crappy (AI) music, and a little thought experiment will rejuvenate you from all the coding. This is a fun (and important) task, we promise!* A few companies create AI models that allow users to produce music through a prompt, much like how you prompt ChatGPT for a midterm essay (please don't do this). Suno is one such company. If you haven't used this technology, watch [this 6-min video](https://www.youtube.com/watch?v=PaFZNuBXlEU) of Suno's CEO explaining what Suno is. **Task 9**: Using three words, document your immediate, gut reaction to this in a comment (anything goes!). Many controversies surround an AI model like Suno: Did artists consent to having their music used in AI training sets? How is AI music being distributed? Just as Hollywood screenwriters unionized against AI in writing (check out [this 1-min video](https://www.youtube.com/watch?v=ovkTViBhMvU)!), how might models like Suno impact artists' livelihoods? We'll unpack this one by one. **Task 10**: Consider the anxiety around humans being replaced by AI. In a multi-line comment, write down 4 different types of music use cases (eg. commercial music for advertisement, pop songs in radio, etc--you can definitely use these examples!). For each use case, brainstorm: How easy or hard is it for this use case be replaced by AI? How is this use case impacted by AI in contrast to the other use cases? Justify your rationale! Once you've written down your answers, think if there's a pattern among the differences. Why do some forms of music seem easier to replace, while others do not? Note that there's no right answer here--we just want to see you make the link between technology's impact and existing social structures! **Task 11**: Many are suing companies like Suno (as well as OpenAI, MidJourney... you name it) over matters like livelihood and copyright. Suno is likewise involved in similar lawsuits. Read about the ["Say No to Suno" campaign](https://www.musicbusinessworldwide.com/artist-representatives-launch-say-no-to-suno-campaign-ai-slop-dilutes-the-royalty-pools-of-legitimate-artists-from-whose-music-this-slop-is-derived/), launched by a coalition of independent artists. Also read this reddit thread from the SunoAI community on [Suno's lawsuit with the music labels](https://www.reddit.com/r/SunoAI/comments/1ok9tsz/tldr_a_lawyers_perspective_on_sunoudio_lawsuits/) (Pay some attention to the discourse: what perspectives are you reading about from the SunoAI community?). These sources mentioned some stakeholders in the lawsuit: the AI company, the music labels, and the independent artists. They all seem to demand different things. In a multi-line comment, explain: What is the future of AI music that each stakeholder would most like to see? And brainstorm: Who/what gets to decide which future we eventually arrive at? If you feel like the three stakeholders raised above do not capture the full image, feel free to include other stakeholder groups in your analysis as well. Hopefully, this exploration demonstrated that AI's impact is not uniform. Rather, the technology interacts with existing social structures (eg. power imbalance between label and artists; commercial nature of certain art forms; etc) to produce different impacts. This demonstrates that AI is a ***sociotechnical system***. Hold on to this term; we will come back to this in a few assignments. Meanwhile, congrats on answering all the questions! If you're curious to learn more: Suno and Udio, the other major AI music model, recently settled with the major music labels, announcing an official partnership. Read [this article](https://www.forbes.com/sites/virginieberger/2025/06/06/what-suno-and-udios-ai-licensing-deals-with-music-majors-could-mean-for-creators-rights/) if you want to know what is happening. Feel free to write down any additional notes on your homework submission. This will not be graded, but we're excited to see what you think! ## Check Block (Autograder Compatibility) When you've completed the above tasks, copy the following check block into the bottom of your code file. Then, hit "Run". All the tests should pass: if they don't, this means you have a typo in a function header. ``` check "function name and input checks": exists = lam(f): true end t = table: name :: String, line-count :: Number end check_list = [list:] find-charactersB(check_list) find-charactersR(check_list) characters-table("") is t count-a-gabriel("gabriel hi", "gomes") is 0 end ``` ## Handin - Download your coding file and make sure it is called `hw4-code.arr`. - Download your tests file from Examplar and make sure it is called `hw4-tests-examples.arr`. - Hand in your files on [Gradescope](https://www.gradescope.com/courses/1358336). ## Theme Song [How D’ya Like Your Eggs in the Morning](https://www.youtube.com/watch?v=zJsYgqQ0zEk) by Dean Martin and Helen O'Connell <!-- ## Staff Spotify Playlist <iframe data-testid="embed-iframe" style="border-radius:12px" src="https://open.spotify.com/embed/playlist/4s1bijxfoTlcOhkDrZBJ1I?utm_source=generator&si=8d888a377cf24331" width="100%" height="352" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe> ------ --> ## [Staff Spotify Playlist](https://open.spotify.com/embed/playlist/4s1bijxfoTlcOhkDrZBJ1I?utm_source=generator&si=8d888a377cf24331) > Brown University CSCI 0111 (Fall 2026) <iframe src="https://docs.google.com/forms/d/e/1FAIpQLSes93TjDZdG7wLuchLdO8E27OJkfE5Uujz3aKoz7bivOFY19A/viewform?usp=dialog" width="640" height="982" frameborder="0" marginheight="0" marginwidth="0">Loading…</iframe>