; next to last item in a list
(syntax-rules ()
(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)