; phone numbers

(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 (mappend f . xss) (apply append (apply map f xss)))

(define (list-minus xs ys)
  (filter (lambda (y) (not (member y ys))) xs))

(define (undigits ds . args)
  (let ((b (if (null? args) 10 (car args))))
    (let loop ((ds ds) (n 0))
      (if (null? ds) n
          (loop (cdr ds) (+ (* n b) (car ds)))))))

(define (phone-numbers len skips)
  (let loop ((len (- len 1))
             (nums (map list (list-minus (range 1 10) skips))))
    (if (zero? len)
        (map undigits (map reverse nums))
        (loop (- len 1)
              (mappend (lambda (xs)
                         (filter (lambda (xs)
                                   (not (= (car xs) (cadr xs))))
                                 (map (lambda (x)
                                        (cons x xs))
                                      (list-minus (range 10) (cons 4 skips)))))
                       nums)))))

(display (phone-numbers 3 '(1 3 5 7 9))) (newline)