; ninety-nine bottles of beer
(define (num->words n)
(letrec ((ones '("" "one" "two" "three" "four" "five" "six"
"seven" "eight" "nine" "ten" "eleven" "twelve"
"thirteen" "fourteen" "fifteen" "sixteen"
"seventeen" "eighteen" "nineteen"))
(tens '("" "" "twenty" "thirty" "forty" "fifty"
"sixty" "seventy" "eighty" "ninety"))
(groups '("" "thousand" "million" "billion" "trillion"
"quadrillion" "quintillion" "sextillion"
"septillion" "octillion" "nonillion" "decillion"
"undecillion" "duodecillion" "tredecillion"
"quattuordecillion" "quindecillion" "sexdecillion"
"septendecillion" "octodecillion" "novemdecillion"
"vigintillion"))
(nnn->words (lambda (n) ; three-digit numbers
(cond ((<= 100 n)
(string-append
(list-ref ones (quotient n 100))
" hundred"
(if (positive? (modulo n 100)) " " "")
(nnn->words (modulo n 100))))
((<= 20 n)
(string-append
(list-ref tens (quotient n 10))
(if (zero? (modulo n 10)) ""
(string-append "-" (list-ref ones (modulo n 10))))))
(else (list-ref ones n))))))
(cond ((negative? n) (string-append "negative " (num->words (- n))))
((<= #e1e66 n) (error 'num->words "out of range"))
((zero? n) "zero")
((< n 1000) (nnn->words n))
(else (let loop ((n n) (groups groups))
(let ((prev (quotient n 1000))
(group (modulo n 1000)))
(string-append
(if (zero? prev) ""
(loop prev (cdr groups)))
(if (zero? group) ""
(string-append
(if (positive? prev) " " "")
(nnn->words group)
(if (string=? "" (car groups)) ""
(string-append " " (car groups))))))))))))
(define (beer n)
(define (upword str)
(string-append (string (char-upcase (string-ref str 0)))
(substring str 1 (string-length str))))
(let ((n-words (upword (num->words n)))
(n1-words (upword (num->words (- n 1)))))
(if (< 1 n)
(begin
(display n-words)
(display " bottles of beer on the wall.")
(newline)
(display n-words)
(display " bottles of beer.")
(newline)
(display "Take one down and pass it around.")
(newline)
(display n1-words)
(display " bottles of beer on the wall.")
(newline)
(newline)
(beer (- n 1)))
(begin
(display "Only one bottle of beer on the wall.")
(newline)
(display "Only one bottle of beer.")
(newline)
(display "Take it down and pass it around.")
(newline)
(display "Now there's no more beer on the wall.")
(newline)))))
(beer 99)