; blum's mental hash
(define f (vector 8 3 7 1 8 5 6 3 0
1 2 7 2 8 4 1 0 4 9 2 5 5 6 7 3 9))
(define g (vector 0 2 9 8 7 3 6 5 1 4))
(define (hash f g str)
(let* ((len (string-length str))
(vec (make-vector len 0))
(out (make-vector len 0))
(next (make-vector 10 0))
(gg (append (vector->list g) (vector->list g))))
; compute next array
(do ((i 0 (+ i 1))) ((= i 10))
(vector-set! next i
(cadr (member i gg))))
; map f over the input string
(do ((i 0 (+ i 1))) ((= i len))
(vector-set! vec i (vector-ref f
(- (char->integer (char-upcase (string-ref str i)))
65))))
; initialize hash
(vector-set! out 0 (vector-ref next (modulo
(+ (vector-ref vec 0) (vector-ref vec (- len 1))) 10)))
; compute remainder of hash
(do ((i 1 (+ i 1))) ((= i len))
(vector-set! out i (vector-ref next (modulo
(+ (vector-ref vec i) (vector-ref out (- i 1))) 10))))
; return result
(list->string
(map (lambda (d) (integer->char (+ d 48)))
(vector->list out)))))
(display (hash f g "abc")) (newline)
(display (hash f g "ProgrammingPraxis")) (newline)