CS 450 Homework 4
Carl Offner
Fall 2009


Due Friday, October 9, 5:00 PM

The problems are collected electronically, as usual, with the exception of Problems 2 and 8. Problems 2 and 8 should be hand-written (unless you really want to use some drawing tool, but I don't think that's worth the effort). Those two problems can be handed in at the beginning of class on Wednesday, October 14. That means at 5:30 PM sharp -- not 5:35 PM. I will not accept either of these problems after the class has started. If for some reason you cannot be present when the class starts, make sure that these problems are in my mailbox in the Math/CS office no later than 5:00 PM.

Actually, if you can get problems 2 and 8 in to me earlier—either in class on Wednesday, October 7 or by scanning them in and emailing them to me, that would be better for all of us. But if you can't then you can hand them in on October 14.

Modified from an assignment of Prof. Bolker

These exercises concern assignment, local state, the environment model, and the beginnings of object oriented programming. That's a lot of new material. It will take getting used to. You will find this material in Sections 3.1 and 3.2 of the text.

Problems 2 and 8 should be written out on paper and handed in as described above.

Put your answers to the rest of the problems in file ASanswers.scm in your new project directory .../cs450/hw4, with discussion when required as Scheme comments. I will load and test your file, so be sure it's bug free. Anything that isn't yet working should be a stub or a comment. Any tests that you ran that are in this file should also be commented out.

  1. Rewrite the make-account procedure on page 223 so that it uses lambda more explicitly. Create several versions, as follows. (Important: please do exactly what each of the three following versions specifies; no more and no less.)
    1. First version: For the first two internal procedure definitions, replace (define (proc args) ...) with (define proc (lambda (args) ...)). Then replace the
          (define (dispatch ...)
          ...
          ...)
          dispatch)
      
      construction with a lambda expression which is evaluated and returned (but of course not called). Call this procedure make-account-lambda.
    2. Second version: Start with a copy of the first version. Then inline the internal procedures deposit and withdraw. That is, replace references to them by the bodies of the procedures. Then you can eliminate the definitions of those procedures. Call this procedure make-account-inline.
    3. Third version (A little extra credit): Start with a copy of the second version. I don't know how to say this without doing it for you, but you might then notice that a lambda can be factored out of the cond in your last version. (If you don't know what I'm talking about here, just ignore this part of the problem.) If you do this, call this new version make-account-inline-factored.

    Note that none of these three versions of make-account contains a dispatch procedure.

  2. In Exercise 3.11 (Page 251), Abelson and Sussman ask you to show how the environment model explains the behavior of make-account. Do that problem twice, once for the function make-account as A&S wrote it, with internal defines, and then again for the function make-account-lambda of problem 1.

    Notes:

  3. Exercise 3.2 (page 224).
  4. The make-monitored procedure you have just constructed can make a monitored version only of a procedure that accepts a single argument. But it would be a nuisance to have to write a separate make-monitored-n for procedures accepting n arguments. And even if you did that you couldn't handle (make-monitored +) . With an explicit call to apply you can write a better make-monitored (call it better-make-monitored) that makes a monitored procedure for a procedure accepting any number of arguments. You will have to learn how to use apply -- read all about it in R5RS.
  5. Exercise 3.3 (page 225). Actually, I want to add to this problem a little, as follows: Let's say that the bank needs to have a way to check the validity of a password on such an account. Here is how I suggest you do this:

    Modify a password account so that it takes a parameter 'check-pw in place of the parameters 'deposit and 'withdraw. The parameter 'check-pw is used to check if a password is correct without performing any transaction on the account. Thus, if

         (define acc (make-pw-account 100 'sicp))
    
    then
         (acc 'sicp 'check-pw) ==> #t
         (acc 'pcis 'check-pw) ==> #f
    
    and
         ((acc 'sicp 'withdraw) 25)  withdraws 25 dollars from the account
    
         ((acc 'pcis 'withdraw) 25)  ignores the 25 and generates an
                                     error message like "Incorrect
                                     password".
    
    Thus, if the second argument to acc is the symbol 'check-pw, the result is either #t or #f.

    In any other case, the result is a function that takes one argument. In that case, if the password is correct, that function does what it's supposed to do. If the password is incorrect, however, the function ignores its argument and just generates an error message. (Note that this would be impossible in a strongly-typed language, where (acc ...) would always have to return a function object.)

    I probably won't actually test this additional capability in this problem. However, you will need this password checking capability when you do the next problem.

    In doing this problem, build on your solution to Problem 1. In fact, see if you can use one of your solutions to Problem 1 as a "black box" -- that is, make the solution to this problem a "wrapper" procedure that just invokes one of the versions of make-account from Problem 1, after handling password checks. In this way, you don't have to copy any of the body of the original make-account procedure. (It isn't necessary that you do it this way -- this is just a suggestion.)

    Call your new function make-pw-account.

  6. Exercise 3.7 (page 236). The way you should interpret the specification for this problem is that the original password works only on the original account, and the new password works only on the new account (which is really a joint account with the original account). So for instance, if we have
    (define acc1 (make-pw-account 100 'pw1))
    (define acc2 (make-joint acc1 'pw1 'pw2))
    then
    ((acc1 'pw1 'deposit) 10) still works, and
    ((acc2 'pw2 'deposit) 10) also works, but
    ((acc1 'pw2 'deposit) 10) does not work, and
    ((acc2 'pw1 'deposit) 10) does not work.
  7. Exercise 3.8 (page 236). How will you test your answer?
  8. Exercise 3.9 (page 243). Let's make it simpler, however: show how to compute (factorial 3) (rather than (factorial 6)). Be sure to read the footnote.