Section 3.1

August 25th 2008 07:00 pm

I have skipped two sections on data-directed programming and generic operations. I have read through most of the texts, but I did not do any exercises for them, it seems boring enough that when I have more time in the future (or when I need the knowledge), I will come back and do the exercises.

I hope I will not skip anymore sections in the future.

Here are my solutions to section 3.1:

Exercise 3.1

This exercise should be quite simple as long as you understands the examples outlined before.

;; 3.1
(define (make-accumulator init)
  (lambda (x)
    (set! init (+ init x))
    init))
"3.1"
(define A (make-accumulator 5))
(A 10)
(A 10)

Exercise 3.2

This exercise is basically a modification to 3.1 with care and attention to the return value of the function.

;; 3.2
(define (make-monitored fun)
  (define calls 0)
  (lambda (x)
    (if (equal? x 'how-many-calls?)
        calls
        (begin
          (set! calls (+ calls 1))
          (fun x)))))
"3.2"
(define s (make-monitored sqrt))
(s 100)
(s 'how-many-calls?)

Exercise 3.3

Some thought (or not) should tell you that only dispatch needs modification, and that is the bottleneck in which all of the request are directed, so as to remove the need to modify every transaction function. One note, I made the wrong-pass function take in one parameter because of a need to return a function that takes in one parameter. Since error cannot be used because there could be more actions with the correct password following it, this is the minimal change action.

(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (wrong-pass any)
    "Incorrect Password")
  (define (dispatch pass m)
    (if (eq? pass password)
        (cond ((eq? m 'withdraw) withdraw)
              ((eq? m 'deposit) deposit)
              (else (error "Unknown request -- MAKE-ACCOUNT" m)))
        wrong-pass))
  dispatch)
 
"3.3"
(define acc (make-account 100 'secret-password))
((acc 'secret-password 'withdraw) 40)
((acc 'some-other-password 'deposit) 50)

Exercise 3.4

This exercise is a simple change to 3.3, same rationale for call-the-cops function taking in one parameter.

;; 3.4
(define (make-account balance password)
  (define cop-counter 0)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (wrong-pass any)
    "Incorrect Password")
  (define (call-the-cops any)
  "calling cops")
  (define (dispatch pass m)
    (cond
      [(eq? pass password)
       (set! cop-counter 0)
       (cond ((eq? m 'withdraw) withdraw)
             ((eq? m 'deposit) deposit)
             (else (error "Unknown request -- MAKE-ACCOUNT" m)))]
      [else
       (set! cop-counter (+ cop-counter 1))
       (if (>= cop-counter 7)
           call-the-cops
           wrong-pass)]))
  dispatch)
"3.4"
(define acc (make-account 100 'secret-password))
((acc 'secret-password 'withdraw) 40)
((acc 'some-other-password 'deposit) 50)
((acc 'some-other-password 'deposit) 50)
((acc 'some-other-password 'deposit) 50)
((acc 'some-other-password 'deposit) 50)
((acc 'some-other-password 'deposit) 50)
((acc 'some-other-password 'deposit) 50)
((acc 'some-other-password 'deposit) 50)

Exercise 3.5

I took Eli’s advice and changed the random-in-range function so it accepts in-exact numbers. Mainly due to plt-scheme’s insistence on being precise whenever possible, such as using fractions when I want decimals.

;; 3.5
(define (random-in-range low high)
  (let ([range (- high low)])
    (+ low (* (random) range))))
 
(define (monte-carlo trials experiment)
  (define (iter trials-remaining trials-passed)
    (cond ((= trials-remaining 0)
           (/ trials-passed trials))
          ((experiment)
           (iter (- trials-remaining 1) (+ trials-passed 1)))
          (else
           (iter (- trials-remaining 1) trials-passed))))
  (iter trials 0))
 
(define (estimate-integral p x1 x2 y1 y2)
  (define (ei)
    (p (random-in-range x1 x2) (random-in-range y1 y2)))
  (let* ([trials 1000000]
         [success (monte-carlo trials ei)])
    (* (- x2 x1) (- y2 y1) success)))
 
(define (unit-circle x y)
  (<= (+ (* x x) (* y y)) 1))
 
"3.5"
(estimate-integral unit-circle -1.0 1.0 -1.0 1.0)

Exercise 3.6

This question is simple if you look through the scheme documentation and find random-seed. random-seed basically seeds the random generator with the value specified.

;; 3.6
(define (rand symb)
  (cond
    [(eq? symb 'generate) (random)]
    [(eq? symb 'reset) random-seed]))
"3.6"
(rand 'generate)
((rand 'reset) 0)
(rand 'generate)
(rand 'generate)
((rand 'reset) 0)
(rand 'generate)
(rand 'generate)

Exercise 3.7

For this exercise, it could be simple if it does not have the requirement that make-joint should fail when the second argument is not the correct password. If it does not have that requirement, then there is no need to modify the make-account function at all. Since it has that, I added a way to check the account password into the make-account from 3.3.

;; 3.7
(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount))
               balance)
        "Insufficient funds"))
  (define (deposit amount)
    (set! balance (+ balance amount))
    balance)
  (define (wrong-pass any)
    "Incorrect Password")
  (define (check-pass pass)
    (eq? pass password))
  (define (dispatch pass m)
    (if (eq? m 'check-pass)
        check-pass
        (if (eq? pass password)
            (cond ((eq? m 'withdraw) withdraw)
                  ((eq? m 'deposit) deposit)
                  (else (error "Unknown request -- MAKE-ACCOUNT" m)))
            wrong-pass)))
    dispatch)
 
(define (make-joint acc orig-pass new-pass)
  (define (wrong-pass any)
    "Incorrect Password")
  (if ((acc orig-pass 'check-pass) orig-pass)
      (lambda (pass m)
        (if (eq? pass new-pass)
            (acc orig-pass m)
            wrong-pass))
      wrong-pass))
 
"3.7"
(define peter-acc (make-account 100 'open-sesame))
((peter-acc 'open-sesame 'withdraw) 40)
(define paul-acc
  (make-joint peter-acc 'open-seasame 'rosebud))
((paul-acc 'rosebud 'withdraw) 40)

Exercise 3.8

This question took me a while to get simple enough. Basically, the question asks you to flip a switch on the first pass and return 0 on the second pass, thus yield the result. For example, if evaulated from right to left, question asks (+ (f 0) (f 1)) to return 1. From my understanding, it is asking for a function f that when it pass over (f 1), it sets a state variable to 1, and then when it pass over (f 0), it returns 0. Same logic goes for the other way. Another note is how to test the program, we can force the excution one way or another by seperating out the function calls. If we want to evalulate (f 1) first, we just put it before (f 0).

;; 3.8
(define f
  (let ([state -1])
    (lambda (x)
      (cond
        [(= state -1) (set! state x) x]
        [else 0]))))
"3.8"
(f 1)
(f 0)

Posted by Jason under Uncategorized | No Comments »

Trackback URI | Comments RSS

Leave a Reply