Consider the following procedure to add 2 to each element in a list:
(define simple-add2 (lambda (L) ;Pre-condition: L is a list of numbers ;Post-condition: returns a new list where 2 is added to each value in L (if (null? L) '() (cons (+ 2 (car L)) (simple-add2 (cdr L)))) ) )
(define simple-add2-trace (lambda (L) ;Pre-condition: L is a list of numbers ;Post-condition: returns a new list where 2 is added to each value in L (display L) (newline) ;;NEW: print out current list on separate line (if (null? L) '() (cons (+ 2 (car L)) (simple-add2-trace (cdr L)))) ) )Here, display is a procedure that prints out the argument that follows on your computer screen. newline moves to a new line on the screen. Thus, in the above code, the current list L will be shown at the screen on a line by itself, each time simple-add2-trace is called recursively.
Experiment further with display and newline.
(define simple-add2-trace (lambda (L) ;Pre-condition: L is a list of numbers ;Post-condition: returns a new list where 2 is added to each value in L ;;; Step 1: print the list on the screen (display L) ;;; Step 2: move to a new line on the screen (newline) ;;; Step 3: process L (if (null? L) '() (cons (+ 2 (car L)) (simple-add2-trace (cdr L)))) ) )This need to execute several steps in a row arises with some frequency in Scheme. More generally, multiple statements are automatically allowed:
(define simple-add2-trace (lambda (L) ;Pre-condition: L is a list of numbers ;Post-condition: returns a new list where 2 is added to each value in L (begin ;;; Step 1: print the list on the screen (display L) ;;; Step 2: move to a new line on the screen (newline) ;;; Step 3: process L (if (null? L) '() (cons (+ 2 (car L)) (simple-add2-trace (cdr L)))) ) ) )An explicit begin expression is required when our code involves multiple steps, but where the rules for an implicit begin do not apply. Such circumstances commonly arise within an if expression, such as the following:
(if (fire?) (begin (go-outside) (call-fire-dept) ) (begin (get-potato-chips) (turn-on-tv) ) )Here, the if is a special form that requires a single expression for the then and else parts; a begin must be used if multiple things must be done. As a further example, consider the following modification of simple-add2-trace>.
(define simple-add2-trace (lambda (L) ;Pre-condition: L is a list of numbers ;Post-condition: returns a new list where 2 is added to each value in L (display L) (if (null? L) (begin (display " then clause") (newline) '() ) (begin (display " else clause") (newline) (cons (+ 2 (car L)) (simple-add2-trace (cdr L))) ) ) ) )
(define simple-add2-trace (lambda (L) ;Pre-condition: L is a list of numbers ;Post-condition: returns a new list where 2 is added to each value in L (display L) (if (null? L) (begin '() (display " then clause") (newline) ) (begin (cons (+ 2 (car L)) (simple-add2-trace (cdr L))) (display " else clause") (newline) ) ) ) )
Problem: Write a procedure that reads 3 scores from the keyboard and averages them:
Solution: The read procedure gets one value from the keyboard; thus, we use this procedure 3 times in our computation:
(define average-3 (lambda () ;Pre-condition: None ;Post-condition: returns the average of 3 numbers read from the keyboard (display "Enter three numbers: ") (display (/ (+ (read) (read) (read)) 3.0)) (display " is the average of the three numbers") (newline) ) )When we run this program to average the numbers 3, 5, and 10, we might have the following interaction with the computer:
> (average-3) Enter three numbers: 3 5 10 6.0 is the average of the three numbersHere, we began processing by calling the procedure with (average-3). Note that this procedure does not require any parameters.
When the program runs, the first display procedure prompted the user to enter some numbers. Then, before the next display can finish, three values must be read and averaged. Each call to procedure read fetches the next value, and the average then is computed.
Write an average procedure which reads successive numbers until 0 is entered and computes and prints the average of these numbers. Be sure you do not include 0 in your computation of the average.
Note: In this problem, the number 0 is called a sentinel. Generally, a sentinel is a value read that tells the computer something special about how processing should proceed.
Number Square Root 1 1.00000 2 1.41421 3 1.73205 4 2.00000 5 2.23607Here, the procedure asks the user to provide a number n and then prints the square roots from 1 to n. In this work, the title is printed only once, while the other lines involve different numbers. Thus, in our first attempt, we write a main procedure for the title and a helping function for the lines:
(define sqrt-table (lambda (n) (display "Number Square Root") (newline) (sqrt-table-helper n) ) ) (define sqrt-table-helper (lambda (n) (if (>= n 1) (begin (sqrt-table-helper (- n 1)) (display n) (display (sqrt n)) (newline)) ) ) )While this approach almost works, the format of the result is not acceptable:
Number Square Root 11 21.4142135623730951 31.7320508075688772 42 52.23606797749979In reviewing this output, at least two difficulties are apparent. First, the two numbers (n and its square root) are printed next to each other. Second, the number of decimal places for each value varies. The solution to such troubles is to specify the format of the output.
Generally, Scheme solves this problem by providing many approaches to convert numbers to strings and to manipulate strings. However, Scheme does not have standard procedures to for formatted output. For this course, therefore, we will use a customized package ~walker/151s/labs/write-formatted.ss.
To use this package, load it in your Scheme work:
(load "~walker/151s/labs/write-formatted.ss")Then use procedures write-int and write-real for formatting integer and real numbers, respectively. The write-int procedure asks for the number to be printed and the width of the field for printing. In our example, we want 4 spaces for our integer
(write-int n 4)Similarly, for real numbers, we supply write-real with the number to be printed, the total width for printing the number, and the desired number of decimal places. In this example, the number takes 14 characters overall, with 5 decimal place accuracy:
(write-real (sqrt n) 14 5)
display
statements in
sqrt-table-helper
by the corresponding write-int
and write-real statements, and check that the new formatting works
as required.
write-int
with various integers and widths to check that
it runs correctly. What happens if write-int
is given a width
that is narrower than required by the number to be printed (e.g., 2 spaces
allocated for the printing of 456)?
This document is available on the World Wide Web as
http://www.math.grin.edu/~walker/courses/153.sp00/lab-i-o.html