(module list-util mzscheme
  
  (provide lookup
           trim-list
           repeat-list
           end-list
           index-of)
  
  ;; lookup: (listof X) (Y -> Boolean) (X -> Y) (Y -> Z) -> (list-of Z)
  ;; Lookup from a list using pred? to choose things accessed by
  ;;   'acc', if pred? returns #t then use 'res' to get the result
  (define (lookup lst pred? acc res)
    (lookup* lst pred? acc res '()))
  
  ;; lookup*: (listof X) (Y -> Boolean) (X -> Y) (Y -> Z) (list-of Z) -> (list-of Z)
  ;; Lookup from a list using pred? accumulating the results
  (define (lookup* lst pred? acc res ret)
    (if (null? lst) ret
        (let ((nret (if (pred? (acc (car lst))) 
                        (cons (res (car lst)) ret)
                        ret)))
          (lookup* (cdr lst) pred? acc res nret))))

  
  ;; trim-list: (listof Any) Number -> (listof Any)
  ;; Trim off the end of the list, leaving at most 'n' elements
  (define (trim-list lst n)
    (if (or (null? lst) (= n 0)) '()
        (cons (car lst) (trim-list (cdr lst) (- n 1))))) 

  ;; end-list: (listof Any) Number -> (listof Any)
  ;; remove the first 'n'elements of the list, returning the end
  (define (end-list lst n)
    (cond [(null? lst) '()]
          [(= n 0) lst]
          [else (end-list (cdr lst) (- n 1))])) 
  

  ;; repeat-list: X Number -> (listof X)
  ;; Create a List of x that is has 'n' elements
  (define (repeat-list x n)
    (if (= n 0) '()
        (cons x (repeat-list x (- n 1)))))
  
  ;; index-of: (X -> boolean) (listof X) -> number
  ;; Return the index of the first element for which pred? returns true
  (define (index-of pred? lst)
    (index-of-start pred? lst 0))

  ;; index-of: (X -> boolean) (listof X) number -> number
  ;; Return the index of the first element for which pred? returns true
  ;;   starting at index 'n'
  (define (index-of-start pred? lst n)
    (cond [(null? lst) -1]
          [(pred? (car lst)) n]
          [else (index-of-start pred? (cdr lst) (+ n 1))]))
)