list-utils.scm 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. #| -*-Scheme-*-
  2. Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
  3. 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
  4. 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Massachusetts
  5. Institute of Technology
  6. This file is part of MIT/GNU Scheme.
  7. MIT/GNU Scheme is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11. MIT/GNU Scheme is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with MIT/GNU Scheme; if not, write to the Free Software
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301,
  18. USA.
  19. |#
  20. ;;;; List utilities
  21. (declare (usual-integrations))
  22. #|
  23. ;;; The following is like symbol<? except that shorter symbols are
  24. ;;; by default less than longer ones.
  25. (define (variable<? x y)
  26. (guarantee-symbol x 'VARIABLE<?)
  27. (guarantee-symbol y 'VARIABLE<?)
  28. (let ((sx (system-pair-car x))
  29. (sy (system-pair-car y)))
  30. (let ((lx (string-length sx))
  31. (ly (string-length sy)))
  32. (if (fix:< lx ly)
  33. #t
  34. (let loop ((i 0))
  35. (cond ((fix:= i ly)
  36. (fix:< lx ly))
  37. ((fix:= (vector-8b-ref sx i)
  38. (vector-8b-ref sy i))
  39. (loop (fix:+ i 1)))
  40. (else
  41. (fix:< (vector-8b-ref sx i)
  42. (vector-8b-ref sy i)))))))))
  43. ;;; This has a bug!
  44. |#
  45. (define (variable<? x y)
  46. (guarantee-symbol x 'VARIABLE<?)
  47. (guarantee-symbol y 'VARIABLE<?)
  48. (symbol<? x y))
  49. ;;; Ok to pass it an improper list
  50. (define (safe-map f pairs)
  51. (cond ((null? pairs) '())
  52. ((pair? pairs)
  53. (cons (f (car pairs))
  54. (safe-map f (cdr pairs))))
  55. (else (f pairs))))
  56. (define (count-elements p? l)
  57. (let loop ((count 0) (l l))
  58. (cond ((null? l) count)
  59. ((p? (car l)) (loop (fix:+ count 1) (cdr l)))
  60. (else (loop count (cdr l))))))
  61. (define (find-first pred lst)
  62. (cond ((null? lst) #f)
  63. ((pred (car lst)) (car lst))
  64. (else (find-first pred (cdr lst)))))
  65. (define (countsymbols exp)
  66. (cond ((pair? exp)
  67. (fix:+ (countsymbols (car exp))
  68. (countsymbols (cdr exp))))
  69. ((symbol? exp) 1)
  70. (else 0)))
  71. (define (butlast l)
  72. (if (null? (cdr l))
  73. '()
  74. (cons (car l)
  75. (butlast (cdr l)))))
  76. (define (last l)
  77. (car (last-pair l)))
  78. (define (list-transpose l)
  79. (apply map list l))
  80. (define (list-index-of x lst)
  81. (cond ((null? lst)
  82. (error "Not in list -- LIST-INDEX-OF" x))
  83. ((equal? x (car lst)) 0)
  84. (else (fix:+ (list-index-of x (cdr lst)) 1))))
  85. (define (delete-nth n list)
  86. (if (fix:= n 0)
  87. (cdr list)
  88. (cons (car list)
  89. (delete-nth (fix:- n 1) (cdr list)))))
  90. (define* ((list:elementwise proc) . lists)
  91. (apply map proc lists))
  92. ;;; MAP-DISTINCT-PAIRS APPLYs a procedure, F, to every distinct pair
  93. ;;; of values chosen from the list, M, producing a list of the
  94. ;;; results.
  95. (define (map-distinct-pairs f lst)
  96. (map (lambda (p) (apply f p))
  97. (distinct-pairs lst)))
  98. (define (distinct-pairs lst)
  99. (if (null? lst)
  100. '()
  101. (let ((f (car lst))
  102. (r (distinct-pairs (cdr lst))))
  103. (let loop ((left (cdr lst)))
  104. (if (null? left)
  105. r
  106. (cons (list f (car left))
  107. (loop (cdr left))))))))
  108. (define (for-each-distinct-pair proc list)
  109. (if (not (null? list))
  110. (let loop ((first (car list)) (rest (cdr list)))
  111. (for-each (lambda (other-element)
  112. (proc first other-element))
  113. rest)
  114. (if (not (null? rest))
  115. (loop (car rest) (cdr rest))))))
  116. (define* ((fringe-smaller-than? n) expr)
  117. (define (walk expr count next)
  118. (cond ((int:> count n) #f)
  119. ((pair? expr)
  120. (walk (car expr) count
  121. (lambda (count)
  122. (walk (cdr expr) count next))))
  123. ((null? expr)
  124. (next count))
  125. (else
  126. (next (int:+ count 1)))))
  127. (walk expr 0 (lambda (count) count)))
  128. #|
  129. ((fringe-smaller-than? 3) '())
  130. ;Value: 0
  131. ((fringe-smaller-than? 100) '(a (b c) d))
  132. ;Value: 4
  133. ((fringe-smaller-than? 3) '(a (b c) d))
  134. ;Value: #f
  135. |#
  136. (define (split-list list predicate recvr)
  137. (let split ((list list)
  138. (recvr recvr))
  139. (if (not (pair? list))
  140. (recvr '() '())
  141. (split (cdr list)
  142. (lambda (win lose)
  143. (if (predicate (car list))
  144. (recvr (cons (car list) win)
  145. lose)
  146. (recvr win
  147. (cons (car list) lose))))))))
  148. (define (find-infimum list predicate)
  149. (if (null? list)
  150. (error "find-infimum: empty list" list))
  151. (let loop ((current (car list))
  152. (left (cdr list)))
  153. (cond ((null? left)
  154. current)
  155. ((predicate (car left) current)
  156. (loop (car left) (cdr left)))
  157. (else
  158. (loop current (cdr left))))))
  159. (define (subst new old where)
  160. (cond ((eq? where old)
  161. new)
  162. ((not (pair? where))
  163. where)
  164. (else
  165. (cons (subst new old (car where))
  166. (subst new old (cdr where))))))
  167. (define (delq-once element list)
  168. (cond ((null? list)
  169. '())
  170. ((eq? (car list) element)
  171. (cdr list))
  172. (else
  173. (cons (car list)
  174. (delq-once element (cdr list))))))
  175. (define (substitute-multiple expression dictionary)
  176. (define (walk e)
  177. (if (pair? e)
  178. (cons (walk (car e)) (walk (cdr e)))
  179. (let ((v (assoc e dictionary)))
  180. (if v
  181. (cadr v)
  182. e))))
  183. (walk expression))
  184. ;;;; Mapping and reducing
  185. ;; Important: All of these are iterative, so they won't run out of stack!
  186. (define* (map&reduce procedure combiner null-value list1 #:optional list2 . lists)
  187. ;; (reduce combiner null-value (map procedure list1 list2 . lists))
  188. (cond ((default-object? list2)
  189. (let loop ((result null-value)
  190. (l list1))
  191. (if (null? l)
  192. result
  193. (loop (combiner (procedure (car l))
  194. result)
  195. (cdr l)))))
  196. ((null? lists)
  197. (let loop ((result null-value)
  198. (l1 list1)
  199. (l2 list2))
  200. (if (or (null? l1) (null? l2))
  201. result
  202. (loop (combiner (procedure (car l1) (car l2))
  203. result)
  204. (cdr l1)
  205. (cdr l2)))))
  206. (else
  207. (let loop ((result null-value)
  208. (l (cons* list1 list2 lists)))
  209. (if (there-exists? l null?)
  210. result
  211. (loop (combiner (apply procedure (map car l))
  212. result)
  213. (map cdr l)))))))
  214. (define (%append x y)
  215. (if (null? x)
  216. y
  217. (%reverse! (%reverse x '()) y)))
  218. (define* (%reverse! l #:optional tail)
  219. (let loop ((current l)
  220. (new-cdr (if (default-object? tail)
  221. '()
  222. tail)))
  223. (if (pair? current)
  224. (let ((next (cdr current)))
  225. (set-cdr! current new-cdr)
  226. (loop next current))
  227. (begin
  228. (if (not (null? current))
  229. (error "%REVERSE!: Argument not a list" l))
  230. new-cdr))))
  231. (define* (%reverse ol #:optional tail)
  232. (let loop ((l ol)
  233. (accum (if (default-object? tail)
  234. '()
  235. tail)))
  236. (cond ((pair? l)
  237. (loop (cdr l)
  238. (cons (car l) accum)))
  239. ((null? l)
  240. accum)
  241. (else
  242. (error "%REVERSE: Argument not a list" ol)))))
  243. ;;; FBE: '%map' is borken!! Comment it out.
  244. ;; (define* (%map f ol1 #| #:optional ol2 . rest |#)
  245. ;; ;; Important: The circular list hack for multi-argument
  246. ;; ;; map does not work here.
  247. ;; (cond ((default-object? l2)
  248. ;; (%map-1 f ol1))
  249. ;; ((null? rest)
  250. ;; (%map-2 f ol1 ol2))
  251. ;; (else
  252. ;; (let outer ((result '())
  253. ;; (ls (reverse (%map-1 reverse (cons* ol1 ol2 rest)))))
  254. ;; (cond ((pair? (car ls))
  255. ;; (let inner ((args (list (caar ls)))
  256. ;; (next (list (cdar ls)))
  257. ;; (rest (cdr ls)))
  258. ;; (cond ((null? rest)
  259. ;; (outer (cons (apply f args) result)
  260. ;; (reverse! next)))
  261. ;; ((not (pair? (car rest)))
  262. ;; (error "%map: Arguments have different lengths"
  263. ;; (cons* ol1 ol2 rest)))
  264. ;; (else
  265. ;; (inner (cons (caar rest) args)
  266. ;; (cons (cdar rest) next)
  267. ;; (cdr rest))))))
  268. ;; ((there-exists? ls (lambda (x) (not (null? x))))
  269. ;; (error "%map:Arguments have different lengths"))
  270. ;; (else
  271. ;; result))))))
  272. (define-integrable (%map-1 f ol)
  273. (let loop ((result '()) (l1 (reverse ol)))
  274. (cond ((pair? l1)
  275. (loop (cons (f (car l1)) result)
  276. (cdr l1)))
  277. ((null? l1)
  278. result)
  279. (else
  280. (error "%map: Argument not a list" ol)))))
  281. (define-integrable (%map-2 f ol1 ol2)
  282. (let loop ((result '())
  283. (l1 (reverse ol1))
  284. (l2 (reverse ol2)))
  285. (cond ((and (pair? l1) (pair? l2))
  286. (loop (cons (f (car l1) (car l2)) result)
  287. (cdr l1)
  288. (cdr l2)))
  289. ((and (null? l1) (null? l2))
  290. result)
  291. (else
  292. (error "%map: Arguments have different lengths"
  293. ol1 ol2)))))