Welcome to CS111E lab! In the spirit of getting to know one another, form groups of 3-4, introduce yourselves, and answer at least one of the following questions (or make up your own):

Learning objectives

This lab will:

You may well not get through all of this lab, and that is fine. Work with your partner, and understand the code you write rather than racing to the last task.

Getting help

In lab, flag down a TA. You do not have to be stuck to do it, and you do not have to have tried everything first — that is what they are in the room for. Ask early: a pair that spends forty minutes on a typo has lost the part of the lab that was worth doing.

Your partner counts too. Saying out loud what you think the code does is most of debugging, and it is faster than waiting.

After lab, short questions go on Ed, and anything longer is better brought to office hours.

Setup

Part 1Practice with error messages

When writing code, it is common to encounter error messages. This does not only happen when you are learning: because programming languages are very particular about what they allow, professional programmers run into errors constantly while working on a piece of code.

Just like anything else we learn in this course, reading an error message is a skill you can practice. Let us do that now. Say we want to figure out how many digits 111 has. If we remember that string-length tells us how many characters its input has, we might run string-length(111) and see what happens:

Pyret error message reporting that string-length expected a String as its first argument but was given the number 111.
The error from string-length(111).

This message tells us that the first (and only) input to string-length should be a String, which 111 is not. It is okay if that is not immediately obvious to you from the message — as you work more with Pyret, you will pick up on the patterns in the wording. Take a few moments to work out the fix with your partner before opening the answer.

The fix

Because string-length expects a String, we can put quotes around 111 so that Pyret reads the value as a String. Run string-length("111") and see that the error is gone.

Task 1

Each of the lines below produces an error. One at a time, run it in Pyret (in the interactions window is fine), discuss the error, and fix the code so that it runs. (Make assumptions about functionality or order of operations where you need to.)

  1. Draw a small hexagon: regular-polygon("orange", "solid", 6, 100)
  2. Compute a complex math expression: num-sqrt(3*3+4*4)
  3. Get the last two characters of a word: string-substring("bees", 3, 5)
  4. Get the last letter of a word: string-char-at("Frankenstein", string-length("Frankenstein"))
  5. Get the absolute difference of the lengths of two words: num-abs(string-length("Frankenstein", "monster"))

Note: For some of these, you or your partner may spot the problem before you even run the code. Talk about the error message anyway. Part of the point of this task is to get used to individual error messages now, so that they are less alarming when they show up in more complicated code later.

Hint: If you get stuck, browse the Pyret documentation on the Number, String, and Image functions before asking for help.

Checkpoint

Call a TA over once you have finished Task 1.

Part 2Cracking mashers

Your younger sibling is learning how to program and has decided that it would be fun to write functions to alter messages meant for you. They have a collection of 10 functions and they run each of your messages through one of them. They refuse to tell you exactly what the functions do, but if you try to guess, they will confirm whether you are right. We'll refer to their functions as "mashers" because they destroy your message strings.

Hint: The mashers are built from functions in the Pyret String library. Open the documentation and look at how it is structured: you should be able to find a list of names of the available functions (without details) and an entry for each function showing its input/output types and what it does.

What a masher looks like under the hood

provide *
provide-types *

fun masher0(s :: String) -> String:
  doc: "returns the first letter of the string"
  string-substring(s, 0, 1)
end

check "masher0: empty str":
  masher0("") raises "index"
end

check "masher0: general":
  masher0("a") is "a"
  masher0(" ") is " "
  masher0("hello") is "h"
  masher0("1, ") is "1"
end

masher0 takes a string and returns its first letter only. The check blocks make sure it does the right thing on both empty and non-empty strings.

Getting the support code

Put this at the top of your program, before any other code:

import shared-gdrive("lab1-support-f26-e.arr", "1hu65nxLAle8Lj-ih5runEgTDPmI_3e5I") as support

That gives you access to all of the mashers. The masher functions are named

support.masher1,
support.masher2,
support.masher3,
...
support.masher10

They take Strings as input — support.masher1("mystery") — and produce a mashed result.

Task 2

Work through the ten mashers. For each one, try inputs until you can say what it does. Keep a record (in your file) of which Strings you used to test each masher. You should be ready to explain your choices to a TA; the strings will also be useful in a later activity.

As you figure out each one, write your own function guess1, guess2, etc that you believe makes the same modification to a given string. To see if you are correct, pass the name of your guess function to the corresponding checker function as follows:

support.test-masher1(guess1)

More hints
  • Vary your inputs, and think about why that helps. In what ways can a String vary?
  • Think about where you see strings of text in the wild — a book, a report. What symbols show up there besides letters?
  • Strings in Pyret are 0-indexed: the first character is at index 0, not 1.
  • At least one masher is the composition of two or more of the earlier ones — it applies one masher to the string and then a different one to that result.

Checkpoint

Call a TA over three times as you work through Task 2:

  1. after you have finished mashers 1–4;
  2. after you have finished mashers 5–8;
  3. once you have finished mashers 9–10.
If you find you are stuck on a masher for too long, just move on to the next one. You can come back to others later if you have time; more practice is better than having identified more mashers.

Task 3

Stop for a moment and reflect on how you approached this problem: how did you go about coming up with test inputs at the beginning? Did your approach change, or did you learn any techniques that you tried on the later examples? Write some preliminary instructions, as if you were teaching a classmate who missed lab how to approach this.

Put your answers in the worksheet that you generated at the beginning of lab.

Are you smarter than an LLM?

111E hopes to help you build understanding of how the capabilities of humans and LLMs or Agents differ. To that end, let's see how Gemini would do with different versions of figuring out how the mashers work. Open Gemini via this link.

Task 4

Give Gemini the "your younger sibling" paragraph from above (without the hint) and ask it to generate a collection of strings that you could give to test mashers. Look at the set of strings it gave back. How do these strings differ from yours (think about traits of the strings, not their specific content)? How effective do you think those strings would be?

Now tell Gemini about the hint, making sure to include the String library URL. Is the collection of strings noticeably different? Can you describe how? Part of what we're doing here is warming up on critiquing what agents output, so it's worth some of your time to try to characterize what Gemini came up with again.

Task 5

Try one more time, this time with the instructions you wrote down in the previous reflection task. Does Gemini perform any better?

Task 6

Write down your observations about how Gemini did in each case (in the worksheet)

Challenge: write your own

Now that you are a masher expert, make one of your own and let your classmates take a crack at it.

Optional

Create a new Pyret file. In it, write a masher function in the style of the ones you have been testing (follow the structure shown in Step 1 above, but you can use any function name you like). Then share it on the masher swap spreadsheet: press Publish in your Pyret file, copy the line that begins with import shared-gdrive, and add it to the sheet.

Note: If you do not see the Publish button, make sure you are logged into Pyret with your Brown Google account.

Optional

Import another group's masher from the swap spreadsheet, using the same form of import you used for the support file. Call a TA over if you get stuck.

Optional

Write a function called our-guess that tries to capture the behavior of the other group's new-masher. When you think it works, check with the group that wrote the masher.