lang/private/map.rkt
#lang s-exp "../kernel.rkt"
(provide (rename-out [map2 map]
                     [for-each2 for-each]
                     [andmap2 andmap]
                     [ormap2 ormap]))
  
;; -------------------------------------------------------------------------

(define map2
  (let ([map
         (case-lambda
           [(f l)
            (if (and (procedure? f)
                     (procedure-arity-includes? f 1)
                     (list? l))
                (let loop ([l l])
                  (cond
                   [(null? l) null]
                   [else (cons (f (car l)) (loop (cdr l)))]))
                (map f l))]
           [(f l1 l2)
            (if (and (procedure? f)
                     (procedure-arity-includes? f 2)
                     (list? l1)
                     (list? l2)
                     (= (length l1) (length l2)))
                (let loop ([l1 l1][l2 l2])
                  (cond
                   [(null? l1) null]
                   [else (cons (f (car l1) (car l2)) 
                               (loop (cdr l1) (cdr l2)))]))
                (map f l1 l2))]
           [(f . args) (apply map f args)])])
    map))

(define for-each2
  (let ([for-each
         (case-lambda
           [(f l)
            (if (and (procedure? f)
                     (procedure-arity-includes? f 1)
                     (list? l))
                (let loop ([l l])
                  (cond
                   [(null? l) (void)]
                   [else (begin (f (car l)) (loop (cdr l)))]))
                (for-each f l))]
           [(f l1 l2)
            (if (and (procedure? f)
                     (procedure-arity-includes? f 2)
                     (list? l1)
                     (list? l2)
                     (= (length l1) (length l2)))
                (let loop ([l1 l1][l2 l2])
                  (cond
                   [(null? l1) (void)]
                   [else (begin (f (car l1) (car l2)) 
                                (loop (cdr l1) (cdr l2)))]))
                (for-each f l1 l2))]
           [(f . args) (apply for-each f args)])])
    for-each))

(define andmap2
  (let ([andmap
         (case-lambda
           [(f l)
            (if (and (procedure? f)
                     (procedure-arity-includes? f 1)
                     (list? l))
                (if (null? l)
                    #t
                    (let loop ([l l])
                      (cond
                       [(null? (cdr l)) (f (car l))]
                       [else (and (f (car l)) (loop (cdr l)))])))
                (andmap f l))]
           [(f l1 l2)
            (if (and (procedure? f)
                     (procedure-arity-includes? f 2)
                     (list? l1)
                     (list? l2)
                     (= (length l1) (length l2)))
                (if (null? l1)
                    #t
                    (let loop ([l1 l1][l2 l2])
                      (cond
                       [(null? (cdr l1)) (f (car l1) (car l2))]
                       [else (and (f (car l1) (car l2)) 
                                  (loop (cdr l1) (cdr l2)))])))
                (andmap f l1 l2))]
           [(f . args) (apply andmap f args)])])
    andmap))

(define ormap2
  (let ([ormap
         (case-lambda
           [(f l)
            (if (and (procedure? f)
                     (procedure-arity-includes? f 1)
                     (list? l))
                (if (null? l)
                    #f
                    (let loop ([l l])
                      (cond
                       [(null? (cdr l)) (f (car l))]
                       [else (or (f (car l)) (loop (cdr l)))])))
                (ormap f l))]
           [(f l1 l2)
            (if (and (procedure? f)
                     (procedure-arity-includes? f 2)
                     (list? l1)
                     (list? l2)
                     (= (length l1) (length l2)))
                (if (null? l1)
                    #f
                    (let loop ([l1 l1][l2 l2])
                      (cond
                       [(null? (cdr l1)) (f (car l1) (car l2))]
                       [else (or (f (car l1) (car l2)) 
                                 (loop (cdr l1) (cdr l2)))])))
                (ormap f l1 l2))]
           [(f . args) (apply ormap f args)])])
    ormap))