sicp-ex-3.3



<< Previous exercise (3.2) | Index | Next exercise (3.4) >>


Igor Saprykin

 (define (make-account balance password) 
   (define (withdraw amount) 
         (if (>= balance amount) 
                 (begin (set! balance (- balance amount)) 
                            balance) 
                 "Not enough money")) 
   (define (deposit amount) 
         (set! balance (+ balance amount)) 
         balance) 
   (define (dispatch pass m) 
         (if (not (eq? pass password)) 
                 (lambda (amount) "Wrong password") 
                 (cond ((eq? m 'withdraw) withdraw) 
                           ((eq? m 'deposit) deposit) 
                           (else (error "Unknown call -- MAKE-ACCOUNT" 
                                                    m))))) 
   dispatch) 

Eivind

 ; An easier solution.  
  
 (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 (dispatch p m) 
     (cond ((not (eq? p password)) (lambda (x) "Incorrect password")) 
           ((eq? m 'withdraw) withdraw) 
           ((eq? m 'deposit) deposit) 
           (else (error "Unknown request -- MAKE-ACCOUNT" m)))) 
   dispatch) 
  

altay

 ; An alternative solution with explicitly defined password validator and method getter 
  
 (define (make-account balance initial-password) 
   (define (withdraw amount) 
     (if (>= balance amount) 
         (begin (set! balance (- balance amount)) 
                balance) 
         "Insufficient funds")) 
  
   (define (deposit amount) 
     (set! balance (+ balance amount)) 
     balance) 
  
   (define (get-method m) 
     (cond ((eq? m 'withdraw) withdraw) 
           ((eq? m 'deposit) deposit) 
           (else (error "Unknown method" m)))) 
  
   (define (valid-password? p) 
     (eq? p initial-password))   
  
   (define (dispatch password method) 
     (if (valid-password? password) 
         (get-method method) 
         (lambda _ "Incorrect password"))) 
    
   dispatch) 

Carl Egbert

Here's a solution that uses a high-order make-passworded function, which could be applied to any function with an identical API to the original make-account:

 ;; original make-account function from the text 
 (define (make-account balance) 
   (define (withdraw amount) 
     (if (>= balance amount) 
         (begin (set! balance (- balance amount)) 
                balance) 
         "Insufficient funds")) 
   (define (deposit amount) 
     (set! balance (+ balance amount)) 
     balance) 
   (define (dispatch m) 
     (cond  ((eq? m 'withdraw) withdraw) 
            ((eq? m 'deposit) deposit) 
            (else (error "Unknown request -- MAKE-ACCOUNT" 
                         m)))) 
   dispatch) 
  
  
 (define (make-passworded f) 
   (define (constructor initial password) 
     (define (correct-pass? attempt) 
       (eq? password attempt)) 
     (let ((passworded-f (f initial))) 
       (define (dispatch attempt x) 
         (if (correct-pass? attempt) 
             (passworded-f x) 
             (lambda (x) "incorrect password"))) 
       dispatch)) 
   constructor) 
  
 (define passworded-make-account 
   (make-passworded make-account)) 

CaesarXInsanium

with the builtin apply procedure. I ran grep for the apply procedure on previous code and decided that it was legal.

 (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 (dispatch m) 
     (cond ((eq? m 'withdraw) withdraw) 
           ((eq? m 'deposit) deposit) 
           (else (error "Unknown request -- MAKE-ACCOUNT" 
                        m)))) 
   ;; really is just another wrapper over dispatch which itself is a wrapper 
   (define (make-password-protected password proc) 
     ;; here is was inspired by another person's answer 
     (lambda (first . args) 
       (if (eqv? first password) 
         (apply proc args) 
         "Incorrect Password"))) 
   ;; returns a procedure object as implementation 
   (make-password-protected password dispatch))