(module isbn (normalize-isbn valid-isbn?) (import chicken scheme) (use srfi-1) (define (valid-isbn10-checksum? isbn) (= 0 (modulo (fold (lambda (x y seed) (+ seed (* x y))) 0 (iota 10 10 -1) isbn) 11))) (define (valid-isbn10? isbn) (and (= (length isbn) 10) (valid-isbn10-checksum? isbn))) (define (valid-isbn13-checksum? isbn) (= (last isbn) (- 10 (modulo (fold (lambda (y x s) (+ s (* x y))) 0 (take (circular-list 1 3) 12) (take isbn 12)) 10)))) (define (valid-isbn13? isbn) (and (= (length isbn) 13) (valid-isbn13-checksum? isbn))) (define (valid-isbn? isbn) (or (valid-isbn10? (string->isbn isbn)) (valid-isbn13? (string->isbn isbn)))) (define (string->isbn isbn-str) (let ((isbn (fold (lambda (x s) (if x (cons x s) s)) '() (map (lambda (s) (if (or (equal? s "x") ; XXX this is ugly (equal? s "X")) 10 (string->number s))) (map string (string->list isbn-str)))))) (if (and (= (length isbn) 13) (= (car isbn) 0)) (set-car! isbn 10)) (reverse isbn))) (define (normalize-isbn isbn) (let* ((isbn-orig (reverse (string->isbn isbn))) (isbn (if (and (= (length isbn-orig) 13) (= (car isbn-orig) 10)) (cons 0 (cdr isbn-orig)) isbn-orig))) (fold string-append "" (map number->string isbn)))))