# sicp-ex-3.4

Exercise 3.4 Modify the make-account procedure of exercise 3.3 by adding another local state variable so that, if an account is accessed more than seven consecutive times with an incorrect password, it invokes the procedure call-the-cops.

Igor Saprykin

```

(define (call-the-cops) "Call the cops")
(let ((count 0)
(limit 7))
(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)
(lambda (amount)
(if (> count limit)
(call-the-cops)
(begin (set! count (+ count 1))
(begin (set! count 0)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown call -- MAKE-ACCOUNT"
m))))))
dispatch))
```

This solution has a logic error. It will actually invoke the "call-the-copes" function when there's more than 8 wrong inputs in a row, instead of 7.

This is due to the actual count is got after set!, so we need to change the order.

```           (lambda (amount)
(set! count (+ count 1))
(if (> count limit)
(call-the-cops)
```

My implementation shares the same basic ideas but uses as what I have done for exercise 3.2.

Daniel-Amariei

```

(define (make-accumulator acc)
(lambda (x)
(set! acc (+ acc x))
acc))

(define (call-the-cops) "The cops have been caled!")
(define attempts (make-accumulator 0))
(define (reset-attempts) (attempts (- (attempts 0))))

(reset-attempts) true)
(else (attempts 1)
false)))

(define (withdraw amount)
(cond ((>= balance amount)
(set! balance (- balance amount))
balance)
(else
"Insufficient funds")))

(define (deposit amount)
(set! balance (+ balance amount))
balance)

(lambda (x) (call-the-cops))
((equal? m 'withdraw) withdraw)
((equal? m 'deposit) deposit)
(else (error "Unknown request: MAKE-ACCOUNT" m))))
dispatch)
```

eliyak

I put all the password-checking functionality into a separate internal function called correct-password?. Unfortunately my implementation of scheme does not know how to (call-the-cops).

``` (define (make-account balance password)
(begin
(call-the-cops)
#f)))
(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
((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request -- MAKE-ACCOUNT" m)))
(lambda (x) (display ""))))
dispatch)
```

anonymous

(this code was contributed at the 27 Dec 2013 edit)

```
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount))
balance)
(print "Insufficient funds")))
(define (deposit amount)
(set! balance (+ balance amount))
balance)
(define (dispatch p m)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request -- MAKE-ACCOUNT" m)))
(lambda (x) (print "Incorrect password") (newline))))
true)
false)
(else
(call-the-cops))))
(define (call-the-cops)
(print "Cops called!")
false)
dispatch))
```

Caleb Gossler

I wrapped dispatch in a function that handles the password checking. It keeps dispatch much cleaner.

``` (define (make-account password 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))))

(define invalid-attempts 0)
(cond [(= invalid-attempts 7)
(call-the-cops)]
(set! invalid-attempts 0)
(f m)]
[else
(set! invalid-attempts (+ 1 invalid-attempts))

(define (call-the-cops)
(error "The cops have been called!"))

```

Han Chan

My implementation is much simpler. I just wrap the dispatch function with an "auth-layer" function, which will do the authentication. Then I wrap the "auth-layer" function with a "secure-layer", which will check the error counter and decide to call the cops or not.

``` (define (secure-make-account balance password)

(define error-count 0)

(define (call-the-police) "Too much errors, we have called LAPD")

(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)))
)

(define (auth-layer pass m)
(dispatch m)
(lambda (x) (begin (set! error-count (+ 1 error-count))
(define (secure-layer pass m)
(if (= 2 error-count)
(lambda (x) (call-the-police))
(auth-layer pass m)))

secure-layer)
```

The spec says "accessed more than seven consecutive times..." And so the above code has two problems: first, 2 != 7 and second, "consecutive" means "following one another without interruption." Thus, a matching (i.e. successful) password must reset the error-count.

Sphinxsky

```

(define (withdraw amount)
(if (>= balance amount)
(begin
(set! balance (- balance amount))
balance)
"insufficient funds"))

(define (deposit amount)
(set! balance (+ balance amount))
balance)

(lambda (m)
(let ((wrong-times (monitored 'how-many-calls?)))
(if (= wrong-times 6)
(begin
(monitored 'reset-count)
(call-the-cops))
(monitored
(if (eq? m 'reset-count)
'reset-count
(- 6 wrong-times)))))))

(define counter
(make-monitored
(lambda (m)
(string-append
"You can still enter "
(number->string m)
" wrong times.")))))

(define (dispatch p m)
(begin
(counter 'reset-count)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "unknown request -- MAKE-ACCOUNT" m))))
counter))

dispatch)

```

zxymike93

My solution is not so original but it's plain and simple.

```

(define lock 0)

(begin (set! lock (+ lock 1))
(newline)))

(define (call-the-cops amount)
(error "Bee-boo Bee-boo Bee-boo"))

(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance
(- balance amount))
balance)
"Insufficient funds"))
(define (deposit amount)
(set! balance (+ balance amount))
balance)

(define (dispatch pw m)
(cond [(eq? pw psswd)
(cond ((eq? m 'withdraw) withdraw)
((eq? m 'deposit) deposit)
(else (error "Unknown request:
MAKE-ACCOUNT" m)))]
[else
(cond [(>= lock 6) call-the-cops]

dispatch)
```

Carl Egbert

A solution that uses a high-order, reusable make-passworded function, which should work with any function with an identical API to make-account, and also reuses the make-monitored solution from exercise 3.2:

```
;; original 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)

;; solution from exercise 3.2
(define (make-monitored f)
(let ((count 0))
(define (how-many-calls?)
count)
(define (reset-count)
(set! count 0))
(define (monitored x)
(begin
(set! count (+ 1 count))
(f x)))
(define (dispatch x)
(cond
((eq? x 'how-many-calls?) (how-many-calls?))
((eq? x 'reset-count) (reset-count))
(else (monitored x))))
dispatch))

(define (call-the-cops x) "weeeoooo weeeeoooo weeeeeoooo")

(define (correct-pass? attempt)
(define try-pass?
(make-monitored correct-pass?))
(try-pass? 'reset-count))
(define (failed-attempts)
(try-pass? 'how-many-calls?))

(define (dispatch attempt x)
(if (try-pass? attempt)
(if (< 6 (failed-attempts))
call-the-cops
failed-entry)))
dispatch))
constructor)

```

roy-tobin

Unique here is the straightforward logic cascade at the cond expression that handles all five possible contingencies in as many lines of code.

``` (define (make-account balance passwd)
(let ((access-failures 0))
(define (call-the-cops) (error "Out of the car, longhair!"))
(define (withdraw amount)
(if (>= balance amount)
(begin (set! balance (- balance amount)) balance)
"Insufficient funds"))
(define (deposit amount)
(set! balance (+ balance amount))
balance)
(define (dispatch phrase m)
(if (eq? phrase passwd)
(set! access-failures 0)
(set! access-failures (+ 1 access-failures)))
(cond ((> access-failures 7) (call-the-cops))