Racket I/O

Racket includes various input and output statements, including terminal-based I/O and file I/O. Note that all of these have side effects!

read and print, along with eval, are the procedures needed to write Racket's read-eval-print loop. (See the notes on eval and apply.)

Reading

read is a function that reads one Racket object from the standard input and returns it.

Example:

(define clam (read))
There are some other functions to to read characters without parsing them into Racket objects.

Writing

Racket provides three different ways to print an instance of a built-in value. According to the Reading and Writing Racket Data section of the Guide, these are:

Read the Guide for details if you need them for an assignment or if you are curious. (You won't need to memorize the differences among them for 341 exams.) One thing to remember is that, for simple datatypes, print works so that if you type the output back into the interaction window, you get the same value back. For example, a symbol squid will print as
'squid
so that if you typed in 'squid in the interaction window (the Read-Eval-Print-Loop) you get the symbol back. Similarly a list with three sea creatures prints as
'(octopus squid clam)
On the other hand, if you use write, Racket doesn't put a quote in front of them, for example
squid

(octopus squid clam)

(newline) does the same thing as (display "\n").

Formatted Write

printf supports simple formatting. It takes a format string as an argument, followed by 0 or more things to print. In the the format string, ~a displays the next argument, ~s writes the next argument, and ~v prints the next argument.

Example:

(let ([x 3]
      [y 4])
   (printf " x=~a \n y=~a \n sum=~a \n" x y (+ x y)))
This prints
  x=3
  y=4
  sum=7

This is probably the most useful of the different procedures for writing output if you are doing old-school debugging by inserting print statements in your code at strategic places.

Multiple Forms

Many of the constructs we've discussed so far, including define, let, and cond, allow multiple forms in their bodies. All but the last form is evaluated just for its side effect, and the value of the last form is used. For example:
(define (starfish x)
  (display "this function doesn't do much\n")
  (display "but it does illustrate the point\n")
  (+ x x))
Here the display expressions are evaluated (for their effect) and then the last expression (+ x x) is evaluated and its value returned as the value of the function. Similarly, there can be multiple forms in the body of a let, or the consequent part of a clause in a cond. However, if must have just a single form in its two arms. (Otherwise, how would Racket tell which was which?)

This capability hasn't been of any use in the past, since we haven't had any side effects -- clearly, the only time one would want to use this is if the forms other than the last have some side effect.