Code Review
Compare your solutions
#|
Упражнение 3.24
В реализациях таблиц в этом разделе ключи всегда проверяются на равенство с помощью equal? (который,
в свою очередь, зовется из assoc). Это не всегда то, что нужно. Например, можно представить себе таблицу
с числовыми ключами, где не требуется точного совпадения с числом, которое мы ищем, а нужно только
совпадение с определенной допустимой ошибкой. Постройте конструктор таблиц make-table, который в
качестве аргумента принимает процедуру same-key? для проверки равенства ключей. Make-table должна
возвращать процедуру dispatch, через которую можно добраться до процедур lookup и insert! локальной
таблицы.
|#
(#%require rackunit
compatibility/mlist)
(define (make-table same-key?)
(let ((local-table (mlist '*table*)))
(define (assoc key records)
(cond ((null? records) #f)
((same-key? key (mcar (mcar records))) (mcar records))
(else (assoc key (mcdr records)))))
(define (lookup key-1 key-2)
(let ((subtable (assoc key-1 (mcdr local-table))))
(if subtable
(let ((record (assoc key-2 (mcdr subtable))))
(if record
(mcdr record)
#f))
#f)))
(define (insert! key-1 key-2 value)
(let ((subtable (assoc key-1 (mcdr local-table))))
(if subtable
(let ((record (assoc key-2 (mcdr subtable))))
(if record
(set-mcdr! record value)
(set-mcdr! subtable
(mcons (mcons key-2 value)
(mcdr subtable)))))
(set-mcdr! local-table
(mcons (mlist key-1
(mcons key-2 value))
(mcdr local-table)))))
'ok)
(define (dispatch m)
(cond ((eq? m 'lookup-proc) lookup)
((eq? m 'insert-proc!) insert!)
(else (error "Unknown operation -- TABLE" m))))
dispatch))
(define table-eq (make-table =))
(define get-eq (table-eq 'lookup-proc))
(define put-eq (table-eq 'insert-proc!))
(put-eq 1 2 333)
(check-equal? (get-eq 1 2) 333)
(check-false (get-eq 1 2.0000001))
(define (same-key-epsilon? epsilon)
(lambda (x y)
(if (< (abs (- x y)) epsilon) #t
#f)))
(define table-epsilon (make-table (same-key-epsilon? 0.1)))
(define get-epsilon (table-epsilon 'lookup-proc))
(define put-epsilon (table-epsilon 'insert-proc!))
(put-epsilon 1 2 42)
(check-equal? (get-epsilon 1 2) 42)
(check-equal? (get-epsilon 1 2.001) 42)
(check-equal? (get-epsilon 1.01 2.01001) 42)
(check-false (get-epsilon 1.2 2.1))