ketos 0.12.0

Lisp dialect scripting and extension language
Documentation
;;; A collection of functions that operate on lists.

(export (
         drop drop-while range repeat take take-while zip zip-with
         all any count each filter find foldl foldr index map))

;; Drop the first `n` elements from `li`, returning the remaining elements.
;; If the list is shorter than `n` elements, `()` is returned.
(define (drop n li)
  (let ((length (len li)))
    (if (< n length)
      (slice li n length))))

;; Drop elements while a predicate is satisfied, returning the remaining elements.
(define (drop-while fn li)
  (cond
    ((null li)        ())
    ((fn (first li))  (drop-while fn (tail li)))
    (else             li)))

;; Returns a list representing the range [`start`, `end`).
;;
;; If `start` is omitted, the range begins at `0`.
;;
;; `step` if given, is the interval between values. It must be non-zero.
(define (range a :optional b (step 1))
  (cond
    ((null b)   (range 0 a))
    ((> step 0) (range-pos a b step ()))
    ((< step 0) (range-neg a b step ()))
    (else       (panic "`range` got 0 step"))))

(define (range-pos start end step out)
  (if (>= start end)
    out
    (range-pos (+ start step) end step (append out start))))

(define (range-neg start end step out)
  (if (<= start end)
    out
    (range-neg (+ start step) end step (append out start))))

;; Returns a list containing `n` instances of `elem`.
(define (repeat n elem) (repeat-into (int n) elem ()))

(define (repeat-into n elem out)
  (if (<= n 0)
    out
    (repeat-into (- n 1) elem (append out elem))))

;; Take the first `n` elements from `li`.
;; If the list is shorter than `n` elements, the whole list is returned.
(define (take n li)
  (slice li 0 (min n (len li))))

;; Take elements of a list while a predicate is satisfied.
(define (take-while fn li) (take-while-inner fn li li 0))

(define (take-while-inner fn li orig idx)
  (cond
    ((null li)        orig)
    ((fn (first li))  (take-while-inner fn (tail li) orig (+ idx 1)))
    (else             (slice orig 0 idx))))

;; Returns a list of lists containing corresponding elements from each input list.
;; The result will be as long as the shortest list.
(define (zip li :rest rest)
  (zip-into () (concat (list li) rest)))

;; Calls a function with each successive set of elements from the given lists.
;; The resulting list will be as long as the shortest list.
(define (zip-with fn li :rest rest)
  (map (lambda (li) (apply fn li)) (zip-into () (concat (list li) rest))))

(define (zip-into li inputs)
  (if (any null inputs)
    li
    (zip-into
      (append li (map first inputs))
      (map tail inputs))))

;; Returns whether all elements satisfy a predicate.
(define (all fn li)
  (or (null li)
    (and (fn (first li)) (all fn (tail li)))))

;; Returns whether any element satisfies a predicate.
(define (any fn li)
  (and (not (null li))
    (or (fn (first li)) (any fn (tail li)))))

;; Returns the number of elements satisfying a predicate.
(define (count fn li) (count-inner fn li 0))

(define (count-inner fn li n)
  (if (null li)
    n
    (count-inner fn (tail li)
                 (if (fn (first li)) (+ n 1) n))))

;; Calls a function for each element, discarding the result.
(define (each fn li)
  (if (not (null li))
    (do
      (fn (first li))
      (each fn (tail li)))))

;; Returns a list containing all elements satisfying a predicate.
(define (filter fn li) (filter-into fn li ()))

(define (filter-into fn li out)
  (if (null li)
    out
    (filter-into fn (tail li)
                 (if (fn (first li))
                   (append out (first li))
                   out))))

;; Returns the first element satisfying a predicate.
(define (find fn li)
  (cond
    ((null li)        ())
    ((fn (first li))  (first li))
    (else             (find fn (tail li)))))

;; Returns the given list, left-folded.
(define (foldl fn ini li)
  (if (null li)
    ini
    (foldl fn (fn ini (first li)) (tail li))))

;; Returns the given list, right-folded.
(define (foldr fn ini li)
  (if (null li)
    ini
    (foldr fn (fn (last li) ini) (init li))))

;; Returns the index of the first element satisfying a predicate, or `()`.
(define (index fn li) (index-inner fn li 0))

(define (index-inner fn li n)
  (cond
    ((null li)        ())
    ((fn (first li))  n)
    (else             (index-inner fn (tail li) (+ n 1)))))

;; Returns each element mapped with `fn`.
(define (map fn li) (map-into fn li ()))

(define (map-into fn li out)
  (if (null li)
    out
    (map-into fn (tail li) (append out (fn (first li))))))