Write some functions returning the nth penultimate list element.
$ cat nli.rkt #lang racket (require rackunit) (define (nth-to-last n l) ; Return a pair p. If n is non-negative and l contains ; more than n elements, the car of p is #t and the cdr of ; p is the nth value from the end of l (the last value in ; l is the 0th value from the end of l). Otherwise the ; car of p is #f and the cdr of p is undefined. (define (prep) ; Return list l shorn of the first n elements. If n is ; negative, or l contains less than n elements, return ; the empty list. (if (< n 0) '() (let loop ((l2 l) (n2 n)) (if (or (null? l2) (= n2 0)) l2 (loop (cdr l2) (- n2 1)))))) (define (get-value l) ; Return a pair p. If l is non-empty, the car of p is ; #t and the cdr of p is the head of l. Otherwise the ; car of p is #f and the cdr of p is undefined. (if (null? l) (cons #f #f) (cons #t (car l)))) (let ((h (prep))) (if (null? h) (get-value h) (let loop ((tail l) (head h)) (let ((next-head (cdr head))) (if (null? next-head) (get-value tail) (loop (cdr tail) next-head))))))) (define (penultimate-element l) ; Return a pair p. If l contains more than 1 element, the ; car of p is #t and the cdr of p is the penultimate value ; of l. Otherwise the car of p is #f and the cdr of p is ; undefined. (nth-to-last 1 l)) (define l '()) (check-equal? (car (nth-to-last -1 l)) #f) (check-equal? (car (nth-to-last 0 l)) #f) (check-equal? (car (nth-to-last 1 l)) #f) (check-equal? (car (penultimate-element l)) #f) (set! l '(a)) (check-equal? (car (nth-to-last -1 l)) #f) (check-equal? (nth-to-last 0 l) '(#t . a)) (check-equal? (car (nth-to-last 1 l)) #f) (check-equal? (car (penultimate-element l)) #f) (set! l '(a b)) (check-equal? (car (nth-to-last -1 l)) #f) (check-equal? (nth-to-last 0 l) '(#t . b)) (check-equal? (nth-to-last 1 l) '(#t . a)) (check-equal? (penultimate-element l) '(#t . a)) (check-equal? (car (penultimate-element '())) #f) (check-equal? (car (penultimate-element '(1))) #f) (check-equal? (penultimate-element '(1 2)) '(#t . 1)) (check-equal? (penultimate-element '(1 2 3)) '(#t . 2)) (check-equal? (penultimate-element '(1 2 3 4)) '(#t . 3)) (check-equal? (penultimate-element '(1 2 3 4 5)) '(#t . 4)) ; Zero-origin vs one-origin indexing. (check-equal? (car (nth-to-last 0 '())) #f) (check-equal? (nth-to-last 0 '(1)) '(#t . 1)) (do ((n 1 (+ n 1))) ((= n 7)) (do ((x 1 (+ x 1))) ((= x 7)) (let ((r (if (<= x n) '(#f . #f) (cons #t (- x n))))) (check-equal? (nth-to-last n (range 1 (+ x 1))) r)))) $ mzscheme nli.rkt $