Comp 210 Lab 11: State and a little I/O

set! vs. set-structure-component!, I/O


set! vs. set-structure-component!

We are going to get some practice using set! and set-structure-component!, as introduced in class. As a reminder,

To do:

  1. Develop

         ; factorial-count! : natnum -> natnum
         ; Purpose: Returns the factorial of its argument.
         ; Effects: Increments factorial-counter.
         ; Examples:
         ; #|
         ; > factorial-counter
         ; 0
         ; > (factorial-count! 3)
         ; 6
         ; > factorial-counter
         ; 1
         ; > (factorial-count! 5)
         ; 120
         ; > factorial-counter
         ; 2
         

    While this seems kind of silly, this idea comes up all the time. However, we'd like to hide the counter; if we do, how can we access the counter's value? We'll see examples like that in class.

  2. Using the structure

         ; A posn is a
         ;    (make-posn x y)
         ; where x,y are numbers.
         (define-struct posn (x y))
         
    develop the following two programs.

    posn+! : posn posn -> void changes the fields of the first argument so that, after this call, the first posn will be the sum of the two arguments. E.g., after

         (define posn1 (make-posn 3 8))
         (define posn2 (make-posn 9 1))
         (posn+! posn1 posn2)
         
    then posn1 is (make-posn 11 10).

    foreach-posn+! : list-of-posn posn -> void, which adds the second argument to each of the posns in the list.

  3. Using the structure

         ; A counter is a
         ;    (make-counter name value)
         ; where name is a symbol, and value is anything.
         (define-struct counter (name value))
         
    develop the following two programs.

    count! : symbol list-of-counter -> void, which increments the value of the counter named by the symbol. If the symbol isn't the name of any of the counters, ignore it.

    foreach-count! : list-of-symbol list-of-counter -> void, which increments the values of the corresponding counters, for each of the symbols, ignoring any symbols that don't name any of the counters.


Input and output

Since Scheme automatically displays the result of whatever expression we give it, so far we haven't needed to know how to display something ourselves. Here are a few functions for getting information into and out of our programs. Try them out.

printf debugging

So far, you have used two good techniques for debugging code:

Using printf appropriately can provide one more good technique, by displaying important pieces of information. The most common places to do this are at the beginning of a function, the end of a function, and after a bunch of set! or set-structure-component! assignments. With practice, you'll see that these and other techniques each have strengths and weaknesses.

The following version of factorial doesn't work:

     (define (buggy-factorial n)
         (cond [(zero? n) 1]
               [else      (* (sub1 n) (buggy-factorial (sub1 n)))]))

We will rewrite our code to print out the input(s) and output(s) of the function:

     (define debug? true)  ; do I want to display debugging info?

     (define (buggy-factorial n)
        (if debug? (printf "buggy-factorial input: ~s~n" n))
        (local [(define result
                    (cond [(zero? n) 1]
                          [else      (* (sub1 n) (buggy-factorial (sub1 n)))]))]
            (if debug? (printf "buggy-factorial output: ~s~n" result))
            result))
To do: Use this code on some examples to see what the printed messages look like.

There are several things to note here: