# penultimate elements

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))
(get-value tail)

(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

\$
```