; words on a telephone keypad
(define (make-hash hash eql? oops size)
(let ((table (make-vector size '())))
(lambda (message . args)
(if (eq? message 'enlist)
(let loop ((k 0) (result '()))
(if (= size k)
result
(loop (+ k 1) (append (vector-ref table k) result))))
(let* ((key (car args))
(index (modulo (hash key) size))
(bucket (vector-ref table index)))
(case message
((lookup fetch get ref recall)
(let loop ((bucket bucket))
(cond ((null? bucket) oops)
((eql? (caar bucket) key) (cdar bucket))
(else (loop (cdr bucket))))))
((insert insert! ins ins! set set! store store! install install!)
(vector-set! table index
(let loop ((bucket bucket))
(cond ((null? bucket)
(list (cons key (cadr args))))
((eql? (caar bucket) key)
(cons (cons key (cadr args)) (cdr bucket)))
(else (cons (car bucket) (loop (cdr bucket))))))))
((delete delete! del del! remove remove!)
(vector-set! table index
(let loop ((bucket bucket))
(cond ((null? bucket) '())
((eql? (caar bucket) key)
(cdr bucket))
(else (cons (car bucket) (loop (cdr bucket))))))))
((update update!)
(vector-set! table index
(let loop ((bucket bucket))
(cond ((null? bucket)
(list (cons key (caddr args))))
((eql? (caar bucket) key)
(cons (cons key ((cadr args) key (cdar bucket))) (cdr bucket)))
(else (cons (car bucket) (loop (cdr bucket))))))))
(else (error 'hash-table "unrecognized message")) ))))))
(define (undigits ds . args)
(let ((b (if (null? args) 10 (car args))))
(let loop ((ds ds) (n 0))
(if (null? ds) n
(loop (cdr ds) (+ (* n b) (car ds)))))))
; READ-LINE [PORT]
(define (read-line . port)
(define (eat p c)
(if (and (not (eof-object? (peek-char p)))
(char=? (peek-char p) c))
(read-char p)))
(let ((p (if (null? port) (current-input-port) (car port))))
(let loop ((c (read-char p)) (line '()))
(cond ((eof-object? c) (if (null? line) c (list->string (reverse line))))
((char=? #\newline c) (eat p #\return) (list->string (reverse line)))
((char=? #\return c) (eat p #\newline) (list->string (reverse line)))
(else (loop (read-char p) (cons c line)))))))
; FOR-EACH-PORT READER PROC [PORT]
(define (for-each-port reader proc . port)
(let ((p (if (null? port) (current-input-port) (car port))))
(let loop ((item (reader p)))
(if (not (eof-object? item))
(begin (proc item) (loop (reader p)))))))
(define (sign str)
; telephone keyboard A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
(define keys (vector 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 7 8 8 8 9 9 9 9))
(define (lookup c) (vector-ref keys (- (char->integer c) 65)))
(undigits (map lookup (filter char-alphabetic? (string->list (string-upcase str))))))
(define table (make-hash (lambda (x) x) = (list) 997))
(define (insert word)
(table 'update! (sign word) (lambda (key words) (cons word words)) (list word)))
(define (lookup signature) (sort (table 'lookup signature) string<?))
(for-each-port read-line insert)
(display (lookup 228)) (newline)
(display (lookup 2268)) (newline)
(display (lookup 772947)) (newline)
(display (lookup 12345)) (newline)