; next to last item in a list (define-syntax assert (syntax-rules () ((assert expr result) (if (not (equal? expr result)) (for-each display `( #\newline "failed assertion:" #\newline expr #\newline "expected: " ,result #\newline "returned: " ,expr #\newline)))))) (define (range . args) (case (length args) ((1) (range 0 (car args) (if (negative? (car args)) -1 1))) ((2) (range (car args) (cadr args) (if (< (car args) (cadr args)) 1 -1))) ((3) (let ((le? (if (negative? (caddr args)) >= <=))) (let loop ((x(car args)) (xs '())) (if (le? (cadr args) x) (reverse xs) (loop (+ x (caddr args)) (cons x xs)))))) (else (error 'range "unrecognized arguments")))) (define (next-to-last xs) (cond ((or (null? xs) (null? (cdr xs))) #f) ((null? (cddr xs)) (car xs)) (else (next-to-last (cdr xs))))) (define (test-next-to-last) (assert (next-to-last '()) #f) (assert (next-to-last '(1)) #f) (assert (next-to-last '(1 2)) 1) (assert (next-to-last '(1 2 3)) 2) (assert (next-to-last '(1 2 3 4)) 3) (assert (next-to-last '(1 2 3 4 5)) 4)) (test-next-to-last) (define (nth-to-last n xs) (if (not (positive? n)) #f (let loop ((n n) (leading xs)) (if (null? leading) #f (if (< 1 n) (loop (- n 1) (cdr leading)) (let loop ((trailing xs) (leading (cdr leading))) (if (null? leading) (car trailing) (loop (cdr trailing) (cdr leading))))))))) (define (test-nth-to-last) (assert (nth-to-last 0 '()) #f) (assert (nth-to-last 0 '(1)) #f) (do ((n 1 (+ n 1))) ((= n 7)) (do ((x 1 (+ x 1))) ((= x 7)) (let ((r (if (< x n) #f (- x n -1)))) (assert (nth-to-last n (range 1 (+ x 1))) r))))) (test-nth-to-last)