; aronson's sequence
(define (take-while pred? xs)
(let loop ((xs xs) (ys '()))
(if (or (null? xs) (not (pred? (car xs))))
(reverse ys)
(loop (cdr xs) (cons (car xs) ys)))))
(define (filter pred? xs)
(let loop ((xs xs) (ys '()))
(cond ((null? xs) (reverse ys))
((pred? (car xs))
(loop (cdr xs) (cons (car xs) ys)))
(else (loop (cdr xs) ys)))))
(define (cardinal n) ; a quadrillion is too much for anybody
(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"))
(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 " (cardinal (- n))))
((<= 1000000000000000 n) (error 'cardinal "domain error"))
((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 (ordinal n)
(let* ((oddballs '(("one" . "first")
("two" . "second") ("three" . "third")
("five" . "fifth") ("eight" . "eighth")
("nine" . "ninth") ("twelve" . "twelfth")))
(card-words (cardinal n))
(last-element (list->string (reverse (take-while
char-alphabetic? (reverse (string->list card-words))))))
(beginning (substring card-words 0
(- (string-length card-words) (string-length last-element)))))
(cond ((assoc last-element oddballs) =>
(lambda (x) (string-append beginning (cdr x))))
((char=? #\y (string-ref last-element
(- (string-length last-element) 1)))
(string-append beginning (substring last-element 0
(- (string-length last-element) 1)) "ieth"))
(else (string-append card-words "th")))))
(define (aronson n) ; first n items of aronson's sequence
(let loop ((k 1) (n n) (result (list))
(front (string->list "tisthe")) (back (list)))
(cond ((zero? n) (reverse result)) ; return result
((null? front) ; rearrange queue, reverse back to front
(loop k n result (reverse back) (list)))
((char=? (car front) #\t) ; next item in sequence
(loop (+ k 1) (- n 1) (cons k result) (cdr front)
(append (filter char-alphabetic?
(reverse (string->list (ordinal k))))
back)))
(else ; keep searching for next item in sequence
(loop (+ k 1) n result (cdr front) back)))))
(display (aronson 75)) (newline)