пятница, 7 января 2011 г.

Exercise-3-04


Упражнение 3.4.
Модифицируйте процедуру make-account из упражнения 3.3, добавив еще одну локальную пе-
ременную, так, чтобы, если происходит более семи попыток доступа подряд с неверным паролем,
вызывалась процедура call-the-cops (вызвать полицию).

Решение в лоб

(define max-tryes 7)
(define (call-the-cops arg1 . args) (error "За вами уже выехали"))
(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount)) balance)
        "Недостаточно денег на счете"))
  (define (deposit amount) (set! balance (+ balance amount)) balance)
  (let ((wrong-tryes 0))
    (define (dispatch pass m)
      (if (eq? pass password)
          (begin
            (set! wrong-tryes 0)
            (cond ((eq? m 'withdraw) withdraw)
                  ((eq? m 'deposit) deposit)
                  (else (error "Неизвестный вызов -- MAKE-ACCOUNT" m))))
          (begin (set! wrong-tryes (+ wrong-tryes 1))
                 (if (> wrong-tryes max-tryes) call-the-cops (λ(arg . other)"Неверный пароль")))))
    dispatch))

Но, на самом деле, не для таких решений мы эту книгу читали. Задачи диспетчеризации и ограничения доступа совсем разные и никак не могут укладываться в одной функции написанной программистом в здравом уме.

Вынесем логику по проверке пароля в отдельную функцию
(define (password-checker-wrapper func password max-tryes)
  (define (call-the-cops arg1 . args) (error "За вами уже выехали"))
  (let ((wrong-tryes 0))
    (λ (pass . args)
      (cond ((eq? pass password) (begin (set! wrong-tryes 0)(apply func args)))
            ((= wrong-tryes max-tryes) call-the-cops)
            (else (begin (set! wrong-tryes(+ wrong-tryes 1))
                         (λ(arg . other)"Неверный пароль")))))))

После этого мы можем вернуть make-accountпочти в первозданное состояние лишь завернув dispatch (который остается таким же как и до введение политики безопасности)

(define (make-account balance password)
  (define (withdraw amount)
    (if (>= balance amount)
        (begin (set! balance (- balance amount)) balance)
        "Недостаточно денег на счете"))
  (define (deposit amount) (set! balance (+ balance amount)) balance)
  (define (dispatch m)
    (cond ((eq? m 'withdraw) withdraw)
          ((eq? m 'deposit) deposit)
          (else (error "Неизвестный вызов -- MAKE-ACCOUNT"  m))))
  (password-checker-wrapper dispatch password 7))

Комментариев нет:

Отправить комментарий