Activity: Local state in Scheme

Table of Contents

1. Activity structure

This is an activity not an assignment.That means it is not graded: you won't get formal feedback on it, but it is a great chance to practice with the ideas we've been talking about and it may also guide you through some new ideas. You'll work on it during class, usually with another students, or if you have to miss class, you'll complete it outside of class.

If you're working with someone, you should work in a paired programming style. At any point in time, one of you is "driving," i.e. actually using the keyboard and mouse. The other is actively engaged following along, preventing bugs, and providing ideas. You'll tradeoff who is driving about every 10 minutes, and it's important that regardless of whose computer you're using, you take turns typing and controlling it - the owner of the computer should not be the only one who drives. Before you start coding for a new part of the activity, I strongly encourage you to sketch out your strategy with your partner. You might discuss possible approaches together, and write down some ideas on paper that will then help you when you begin coding.

At the end of class, you should make sure you turn your code in (even if you're not done), as that gives you access to my solutions, and to email the code to your partner (so they can turn it in to access my solutions).

2. Setup

If both you and your partner have computers with you with the tools for our class setup on it, decide whose computer you'll be using.

Them you'll do the activity in VS Code: download the starter code (below), unzip it, move it into the ProgrammingLanguages folder for our Docker container, and then open that folder within the Docker container in VSCode.

Click here to access the starter code for this activity.

3. Tasks

In this activity, you'll be examining and adding to the local state example we talked about in class.

3.1. Understanding local state

main.scm contains a version of the make-account function, always setting balance to 0 to start. Try running it, and make sure you can draw the same type of diagram that I drew to understand where balance is being stored when I do something like:

(define account (make-account))

We could imagine two ways of modifying the code to take in an initial balance parameter, allowing us to start off with some amount of money in the account:

  • Add a parameter and bind it in the let (this is what I demonstrated in class):
(define make-account
    (lambda (initial-balance)
        (let ((balance initial-balance))
            (lambda (amt)
                    (set! balance (- balance amt))
                    balance))))
  • Add a parameter and remove the let:
(define make-account
    (lambda (balance)
        (lambda (amt)
                (set! balance (- balance amt))
                balance)))

How is the diagram you'd draw for a line like (define account (make-account 30)) different for each of these? With the folks at your table, draw the two versions of the environment diagram on the whiteboards. Then, modify the code to add in the parameter balance in one of the two ways above.

3.2. Adding instance variables

We said that we could see make-account as operating similar to a class, with one instance variable. Try adding a second instance variable called max-withdrawal that is initialized to 5; different account holders should be able to have different values for max-withdrawal, as we might later add a method to modify this variable for an account holder based on special request. Modify the code to ensure that if the person tries to withdraw more than the max-withdrawal, no withdrawal occurs. On paper, draw a diagram of the environment if we ran the following:

(define my-acct (make-account 30))
(define cats-acct (make-account 400))
(my-acct 100) ;; doesn't withdraw because > 5
(my-acct 5)
(cats-acct 20)

3.3. Static versus local variables

In the previous section, my-acct and cats-acct had separate max-withdrawal variables, allowing for the potential to set them separately for different account holders. Imagine additionally that we want to have an absolute-max-withdrawal value for all account holders: no one ever gets to withdraw more than 100 at once. Modify make-account so that it declares a variable for absolute-max-withdrawal that will be shared across account holders, similar to a static variable in a class in Java, and always initialize absolute-max-withdrawal to 100.

3.4. Adding methods

Now, we'll try adding methods, callable via message passing. I'd like to be able to write code like:

(define my-acct (make-account 30))
((my-acct "deposit") 15) ;; returns 45, the new amount in my account
((my-acct "withdraw") 3) ;; returns 42

Modify make-account to add these options. Note that equal? will check if two strings are equal.

3.5. Extra time?

If you have extra time, consider how to modify your code to allow changing of the shared absolute-max-withdrawal variable as well as how to set the individual max-withdrawal variables. Draw a diagram for what's happening when you make these changes.

4. Turning in activities

To turn in this activity, zip up the folder with your code, and upload that zip on Moodle. Additionally, email the zip to your partner so they can turn it in too. Even if you worked with a partner or you didn't finish, everyone should turn in the activity in order to gain access to my solutions.