(chapter-start 'list-manipulation "utilities for manipulating and iterating over lists, including filters and transforms") (def zip args ; takes a list of lists, ((p q r) (1 2 3) (a b c) ...), returns ((p 1 a ...) (q 2 b ...) (r 3 c ...)) (if (car args) (cons (map car args) (apply zip (map cdr args))))) ; invokes 'f for each element of 'things, first element processed first ; ( "l" in "eachl" = "leftmost first" ) (def eachl (f things) (loop (pair? things) (do (f (car things)) (= things (cdr things))))) ;; if things is a pair, ;; if (cdr things) is nil, return (car things) ;; else recurse on (cdr things) ;; else return things ;; ;; 'it is used internally ;; (def list/last (things it) (loop (pair? things) (= it (car things) things (cdr things))) (or things it)) ;; finds the index in 'things for which 'f returns non-nil, ;; or nil if not found (def list/find-index (f things) (with (found nil i -1) (loop (and things (no found)) (= found (f (car things)) things (cdr things) i (+ i 1))) (and found i))) ;; finds the index of 'thing in a list 'things, such that for example, ;; given a list 'my-list and an item 'thingy in the list, ;; (nth (list/index-of thingy my-list) my-list) will return the value of thingy. ;; returns nil if not found (def list/index-of (thing things) (list/find-index (fn (it) (eq? it thing)) things)) ;; given a number 'n and a list 'things, return (a b) where a is ;; the item at index n-1 or nil if not possible, and b is the item ;; at index n+1 or nil if not possible (def list/around (n things) (if (and n (< -1 n (len things))) (list (and (> n 0) (nth (- n 1) things)) (nth (+ n 1) things)) (list nil nil))) ;; finds the item before and the item after the given item in the given list. ;; For example, ;; (list/around λx(eq? x 'd) '(a b c d e f) ) will return '(c e) (def list/around-f (f things) (list/around (list/find-index f things) things)) ;; finds the item before and the item after the given item in the given list. ;; For example, ;; (list/around '(a b c d e f) 'd) will return '(c e) (def list/around-thing (thing things) (list/around (list/index-of thing things) things)) ; invokes 'f for each element of 'things, last element processed first ; ( "r" in "eachr" = "rightmost first" ) (def eachr (f things) (eachl f (rev things))) ; assign (cons x things) to things (mac push (x things) `(= ,things (cons ,x ,things))) ;; used internally by 'flatmap (def flatmap-helper (f things res) (loop (pair? things) (let a (car things) (= res (if (pair? a) (flatmap-helper f a res) a (cdr-set res (cons (f a))) res) things (cdr things)))) (if things (= res (set-cdr res (f things)))) res) ;; flatten the given list, transforming each leaf-item, recursively (def flatmap (f things) (let res (cons) (flatmap-helper f things res) (cdr res))) ; flatten the given list, recursively (def flatten (things) (flatmap x1 things)) ; given a list 'al of form '( (k0 v0) (k1 v1) (k2 v2) ... (kn vn) ) and ; a 'key, returns the list (kx vx) from 'al where kx is equal to 'key ; #attribution: inspiration from arc.arc (def assoc (key al) (if (pair? al) (if (caris key (car al)) (car al) (assoc key (cdr al))))) ; given a list 'al of form '( (k0 v0) (k1 v1) (k2 v2) ... (kn vn) ) and ; a 'key, returns vx from 'al where kx is equal to 'key ; #attribution: lifted almost directly from arc.arc (def alref (key al) (cadr (assoc key al)))