Skip to main content

Simple Input in Scheme

Summary
When writing interactive programs, we need a way to get information from our users. In this reading, we explore the simple ways to read information that the user enters on the keyboard.

Introduction

Although the DrRacket program development environment let us write procedures that other people can interact with, those interactions happen primarily by people typing commands in the interactions pane. What if we want to write programs that feel more like “real” programs, ones that prompt the user for information, do some computation, and produce a result. (Okay, those are still pretty simplistic programs.)

We already know ways to output computed results. In this reading, we consider the techniques used in Scheme to read data typed on the keyboard.

Reading Information with read-line

One of the most natural ways to read information from the user is to read a complete line of text. The procedure read-line reads one line that the user types and returns it as a string.

> (read-line)
Hello ; We typed this!
"Hello"

Since you don’t know a lot about strings right now, the main ways that you can use strings is with display, image-load, and image-save.

We’ll notice this most if we do our work in the definitions pane, rather than the interactions pane. For example, consider the following “program” in the definitions pane.

#lang racket
(display "Please enter your name: ")
(define name (read-line))
(display "Hello, ")
(display name)
(newline)

When we run this program, something like the following interaction should happen.

Output! Please enter your name: Sam
Output! Hello, Sam

You can also run these programs from the terminal. Suppose we saved the aforementioned program as hello.rkt. In terminal, we can run it by typing racket hello.rkt.

$ racket hello.rkt
Please enter your name: Sam
Hello, Sam

Okay, it’s not all that exciting, but it’s a start.

Reading Data with read

Unfortunately, the read-line procedure only reads strings. What if we want to read another kind of value, such as a number? In those cases, Scheme provides a procedure named read that reads one value of any type, using the normal Scheme syntax.

Suppose we have the following in the definitions pane.

#lang racket
(display "Please enter a number: ")
(define val (read))
(display val)
(display " cubed is ")
(display (* val val val))
(newline)

When we click the Run button, we should see an interaction that resembles the following. (You should assume that we entered 5 in response to the prompt.)

Output! Please enter a number: 5
Output! 5 cubed is 125

What happens when the user enters something other than a number? You can explore that question in the self check.

Side Effects

Like the output operations (e.g., display and newline), the input operations are operations with side effects. The means that in addition to doing some computation, they also change the state of the world around them. In this case, they read something from the keyboard.

Why does it matter that these operations have side effects? Because it changes how we think about programs in Scheme. Consider the expression (- (square 4) (square 3)). We have to compute the two squares before we subtract. However, does it matter whether we square 4 before we square 3, or whether we square 3 before we square 4? No! Since the two computations are independent, we can do them in either order. We could even do them simultaneously!

Now, let’s consider a similar expression using read: (- (read) (read)). Does it matter whether we read the left value first or the the right value first? Almost certainly! Which will Scheme do? Well, it turns out that the formal definition of Scheme says that it can choose either order. And so this is a very dangerous expression to write—it’s one that may work well most of the time, but misbehave at other times. If we avoid operations with side effects, we avoid these potential confusions.

There are a variety of mechanisms by which we can make it unambiguous what order we want to read and write values. Still, the presence of side effects leads to possible problems in our program design. We will therefore be careful to think about which operations have potential side effects and which do not.

You may even have encountered one operation that has a very unexpected (and often confusing) set of side effects. The image-show operation shows an image in an window, which changes your screen. That’s one kind of side effect. But if you then close that window, GIMP and DrRacket may forget about the image altogether, which is a very different kind of side effect. We may be able to avoid that unexpected effect if we don’t write programs the rely on the number of an image after we call image-show.

Self Checks

Check 1: Reading Strings

Enter the following in the definitions pane.

#lang racket
(display "Please enter a number: ")
(define val (read))
(display val)
(display " cubed is ")
(display (* val val val))
(newline)

a. Determine what happens if you enter your name in response to the prompt.

b. Determine what happens if you enter the number 42 in response to the prompt.

c. Determine what happens if you just hit Enter or Return in response to the prompt.

Check 2: Reading Values

Enter the following in the definitions pane.

#lang racket
(display "Please enter your name: ")
(define name (read-line))
(display "Hello, ")
(display name)
(newline)

a. Determine what happens if you enter the number 42 in response to the prompt.

b. Determine what happens if you enter the number 4.2 in response to the prompt.

c. Determine what happens if you enter the number 4/3 in response to the prompt.

d. Determine what happens if you enter the number 4+2i in response to the prompt.

e. Determine what happens if you enter "42" (including the quotation marks) in response to the prompt.

f. Determine what happens if you enter your name in response to the prompt.

g. Determine what happens if you just hit Enter or Return in response to the prompt.

Check 3: Review

From what you read and from your experiments, what do you see as the differences between read and read-line?