nested-loop.scm 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. ;;; -*- Mode: Scheme -*-
  2. ;;;; Nested Loops with loop, Version 10 (BETA)
  3. ;;; Copyright (c) 2008, Taylor R. Campbell
  4. ;;;
  5. ;;; Redistribution and use in source and binary forms, with or without
  6. ;;; modification, are permitted provided that the following conditions
  7. ;;; are met:
  8. ;;;
  9. ;;; * Redistributions of source code must retain the above copyright
  10. ;;; notice, this list of conditions and the following disclaimer.
  11. ;;;
  12. ;;; * Redistributions in binary form must reproduce the above copyright
  13. ;;; notice, this list of conditions and the following disclaimer in
  14. ;;; the documentation and/or other materials provided with the
  15. ;;; distribution.
  16. ;;;
  17. ;;; * Neither the names of the authors nor the names of contributors
  18. ;;; may be used to endorse or promote products derived from this
  19. ;;; software without specific prior written permission.
  20. ;;;
  21. ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
  22. ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  23. ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
  25. ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  27. ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  28. ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  29. ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30. ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31. ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. (define-syntax nested-loop
  33. (syntax-rules ()
  34. ((NESTED-LOOP continuation ((state initial) ...) combiner
  35. clause0 clause1+ ...)
  36. (%NESTED-LOOP LOOP continuation ((state initial) ...) combiner
  37. clause0 clause1+ ...))))
  38. (define-syntax nested-lazy-loop
  39. (syntax-rules ()
  40. ((NESTED-LOOP continuation ((state initial) ...) combiner
  41. clause0 clause1+ ...)
  42. (%NESTED-LOOP LAZY-LOOP continuation ((state initial) ...) combiner
  43. clause0 clause1+ ...))))
  44. (define-syntax %nested-loop
  45. (syntax-rules (PARALLEL NESTED DO LET LET-VALUES IF NOT AND OR)
  46. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  47. expression)
  48. (LET ((state initial) ...)
  49. (combiner (LAMBDA () expression) continuation)))
  50. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  51. (PARALLEL (iterator ...) ...)
  52. clause0 clause1+ ...)
  53. (looper CONTINUE ((WHERE state initial)
  54. ...
  55. (iterator ...)
  56. ...)
  57. => (continuation state ...)
  58. (%NESTED-LOOP looper (LAMBDA (state ...) (CONTINUE state ...))
  59. ((state state) ...)
  60. combiner
  61. clause0 clause1+ ...)))
  62. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  63. (NESTED clause ...)
  64. clause0 clause1+ ...)
  65. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  66. clause ... clause0 clause1+ ...))
  67. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  68. (DO command ...)
  69. clause0 clause1+ ...)
  70. (BEGIN command ...
  71. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  72. clause0 clause1+ ...)))
  73. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  74. (LET ((variable value) ...))
  75. clause0 clause1+ ...)
  76. (LET ((variable value) ...)
  77. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  78. clause0 clause1+ ...)))
  79. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  80. (LET variable value)
  81. clause0 clause1+ ...)
  82. (LET ((variable value))
  83. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  84. clause0 clause1+ ...)))
  85. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  86. (LET-VALUES ((bvl expression) ...))
  87. clause0 clause1+ ...)
  88. (LET-VALUES ((bvl expression) ...)
  89. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  90. clause0 clause1+ ...)))
  91. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  92. (LET-VALUES bvl expression)
  93. clause0 clause1+ ...)
  94. (LET-VALUES ((bvl expression))
  95. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  96. clause0 clause1+ ...)))
  97. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  98. (IF condition)
  99. clause0 clause1+ ...)
  100. (IF condition
  101. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  102. clause0 clause1+ ...)
  103. (continuation initial ...)))
  104. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  105. ((iterator ...) ...)
  106. clause0 clause1+ ...)
  107. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  108. (PARALLEL (iterator ...) ...)
  109. clause0 clause1+ ...))
  110. ;** This clause must come last! It would shadow the others.
  111. ((%NESTED-LOOP looper continuation ((state initial) ...) combiner
  112. (iterator ...)
  113. clause0 clause1+ ...)
  114. (%NESTED-LOOP looper continuation ((state initial) ...) combiner
  115. (PARALLEL (iterator ...))
  116. clause0 clause1+ ...))))
  117. ;;;; Iteration
  118. (define-syntax iterate*
  119. (syntax-rules (=>)
  120. ((ITERATE* ((state initial) ...) => result stepper clause0 clause1+ ...)
  121. (NESTED-LOOP (LAMBDA (state ...) result)
  122. ((state initial) ...) stepper clause0 clause1+ ...))
  123. ((ITERATE* ((state initial) ...) stepper clause0 clause1+ ...)
  124. (NESTED-LOOP VALUES* ((state initial) ...) stepper
  125. clause0 clause1+ ...))))
  126. (define-syntax iterate
  127. (syntax-rules (=>)
  128. ((ITERATE ((state initial) ...) => result stepper clause0 clause1+ ...)
  129. (ITERATE* ((state initial) ...) => result
  130. (LAMBDA (BODY CONTINUATION)
  131. (RECEIVE (state ...) (stepper (BODY) state ...)
  132. (CONTINUATION state ...)))
  133. clause0 clause1+ ...))
  134. ((ITERATE ((state initial) ...) stepper clause0 clause1+ ...)
  135. (ITERATE* ((state initial) ...)
  136. (LAMBDA (BODY CONTINUATION)
  137. (RECEIVE (state ...) (stepper (BODY) state ...)
  138. (CONTINUATION state ...)))
  139. clause0 clause1+ ...))))
  140. (define-syntax iterate!
  141. (syntax-rules ()
  142. ((ITERATE! clause0 clause1+ ...)
  143. (ITERATE* () ;No state
  144. (LAMBDA (BODY CONTINUATION) (BODY) (CONTINUATION))
  145. clause0 clause1+ ...))))
  146. (define-syntax iterate-values
  147. (syntax-rules (=>)
  148. ((ITERATE-VALUES ((state initial) ...) => result
  149. clause0 clause1+ ...)
  150. (ITERATE* ((state initial) ...) => result CALL-WITH-VALUES
  151. clause0 clause1+ ...))
  152. ((ITERATE-VALUES updater ((state initial) ...) => result
  153. clause0 clause1+ ...)
  154. ;++ This should be visible only in the final expression. However,
  155. ;++ that requires tail patterns, which are non-standard.
  156. (WITH-EXTENDED-PARAMETER-OPERATORS
  157. ((updater (VALUES* (state . state) ...)))
  158. (ITERATE-VALUES ((state initial) ...) => result clause0 clause1+ ...)))
  159. ((ITERATE-VALUES ((state initial) ...) clause0 clause1+ ...)
  160. (ITERATE* ((state initial) ...) CALL-WITH-VALUES
  161. clause0 clause1+ ...))
  162. ((ITERATE-VALUES updater ((state initial) ...) clause0 clause1+ ...)
  163. (WITH-EXTENDED-PARAMETER-OPERATORS
  164. ((updater (VALUES* (state . state) ...)))
  165. (ITERATE* ((state initial) ...) CALL-WITH-VALUES
  166. clause0 clause1+ ...)))))
  167. ;++ Hack for MIT Scheme, whose multiple return values are broken.
  168. (define-syntax values*
  169. (syntax-rules ()
  170. ((VALUES* single) single)
  171. ((VALUES* multiple ...) (VALUES multiple ...))))
  172. ;;;; Recursion
  173. (define-syntax recur*
  174. (syntax-rules ()
  175. ((RECUR* base-case combiner clause0 clause1+ ...)
  176. (NESTED-LOOP (LAMBDA () base-case)
  177. () ;No state
  178. combiner
  179. clause0 clause1+ ...))))
  180. (define-syntax lazy-recur*
  181. (syntax-rules ()
  182. ((LAZY-RECUR* base-case combiner clause0 clause1+ ...)
  183. (NESTED-LAZY-LOOP (LAMBDA () base-case)
  184. () ;No state
  185. combiner
  186. clause0 clause1+ ...))))
  187. (define-syntax recur
  188. (syntax-rules ()
  189. ((RECUR base-case combiner clause0 clause1+ ...)
  190. (RECUR* base-case
  191. (LAMBDA (BODY CONTINUATION)
  192. (combiner (BODY) (CONTINUATION)))
  193. clause0 clause1+ ...))))
  194. (define-syntax lazy-recur
  195. (syntax-rules ()
  196. ((LAZY-RECUR base-case combiner clause0 clause1+ ...)
  197. (LAZY-RECUR* base-case
  198. (LAMBDA (BODY CONTINUATION)
  199. (combiner (BODY) (CONTINUATION)))
  200. clause0 clause1+ ...))))
  201. (define-syntax recur-values
  202. (syntax-rules (=>)
  203. ((RECUR-VALUES base-case => result clause0 clause1+ ...)
  204. (CALL-WITH-VALUES (LAMBDA ()
  205. (RECUR-VALUES base-case clause0 clause1+ ...))
  206. result))
  207. ((RECUR-VALUES base-case clause0 clause1+ ...)
  208. (RECUR* base-case
  209. (LAMBDA (RECEIVER-BODY RECURSION)
  210. (CALL-WITH-VALUES RECURSION (RECEIVER-BODY)))
  211. clause0 clause1+ ...))))
  212. ;;;; Collecting Lists & Streams
  213. (define-syntax collect-list-reverse
  214. (syntax-rules (INITIAL)
  215. ((COLLECT-LIST-REVERSE (INITIAL tail-expression) clause0 clause1+ ...)
  216. (ITERATE ((TAIL tail-expression)) CONS clause0 clause1+ ...))
  217. ((COLLECT-LIST-REVERSE clause0 clause1+ ...)
  218. (COLLECT-LIST-REVERSE (INITIAL '()) clause0 clause1+ ...))))
  219. ;;; The first definition of COLLECT-LIST is probably the one that you
  220. ;;; want. On the other hand, what follows in comments is elegant, and
  221. ;;; shows the flexibility of the mchanism, especially when compared
  222. ;;; with the definition of COLLECT-STREAM.
  223. (define-syntax collect-list
  224. (syntax-rules (INITIAL)
  225. ((COLLECT-LIST (INITIAL tail-expression) clause0 clause1+ ...)
  226. (APPEND-REVERSE (COLLECT-LIST-REVERSE clause0 clause1+ ...)
  227. tail-expression))
  228. ((COLLECT-LIST clause0 clause1+ ...)
  229. (REVERSE (COLLECT-LIST-REVERSE clause0 clause1+ ...)))))
  230. ; (define-syntax collect-list
  231. ; (syntax-rules (INITIAL)
  232. ;
  233. ; ((COLLECT-LIST (INITIAL tail-expression) clause0 clause1+ ...)
  234. ; (RECUR tail-expression CONS clause0 clause1+ ...))
  235. ;
  236. ; ((COLLECT-LIST clause0 clause1+ ...)
  237. ; (COLLECT-LIST (INITIAL '()) clause0 clause1+ ...))))
  238. (define-syntax collect-stream
  239. (syntax-rules (INITIAL)
  240. ((COLLECT-STREAM (INITIAL tail-expression) clause0 clause1+ ...)
  241. (LAZY-RECUR tail-expression STREAM-CONS clause0 clause1+ ...))
  242. ((COLLECT-STREAM clause0 clause1+ ...)
  243. (COLLECT-STREAM (INITIAL STREAM-NIL) clause0 clause1+ ...))))
  244. (define-syntax collect-list!
  245. (syntax-rules (INITIAL)
  246. ((COLLECT-LIST! (INITIAL tail-expression) clause0 clause1+ ...)
  247. (LET ((PAIR (CONS #F tail-expression)))
  248. (COLLECT-LIST-INTO! PAIR clause0 clause1+ ...)
  249. (CDR PAIR)))
  250. ((COLLECT-LIST! clause0 clause1+ ...)
  251. (COLLECT-LIST! (INITIAL '()) clause0 clause1+ ...))))
  252. (define-syntax collect-list-into!
  253. (syntax-rules ()
  254. ((COLLECT-LIST-INTO! pair-expression clause0 clause1+ ...)
  255. (ITERATE* ((PAIR pair-expression))
  256. (LAMBDA (BODY CONTINUATION)
  257. (LET ((TAIL (CONS (BODY) (CDR PAIR))))
  258. (SET-CDR! PAIR TAIL)
  259. (CONTINUATION TAIL)))
  260. clause0 clause1+ ...))))
  261. ;;;; Collecting Vectors and Strings
  262. (define-syntax collect-vector
  263. (syntax-rules ()
  264. ((COLLECT-VECTOR clause0 clause1+ ...)
  265. (LIST->VECTOR (COLLECT-LIST clause0 clause1+ ...)))))
  266. (define-syntax collect-string
  267. (syntax-rules ()
  268. ((COLLECT-STRING clause0 clause1+ ...)
  269. (LIST->STRING (COLLECT-LIST clause0 clause1+ ...)))))
  270. ;;; The following definition of COLLECT-DISPLAY can collect any object,
  271. ;;; whose printed representation is computed using DISPLAY; it relies
  272. ;;; on SRFI 6 (Basic String Ports) to accomplish this.
  273. (define-syntax collect-display
  274. (syntax-rules ()
  275. ((COLLECT-DISPLAY clause0 clause1+ ...)
  276. (LET ((OUTPUT-PORT (OPEN-OUTPUT-STRING)))
  277. (ITERATE* () ;No state
  278. (LAMBDA (BODY CONTINUATION)
  279. (DISPLAY (BODY) OUTPUT-PORT)
  280. (CONTINUATION))
  281. clause0 clause1+ ...)
  282. (GET-OUTPUT-STRING OUTPUT-PORT)))))
  283. ;;;;; Expanding Vector and String Collection
  284. ;;; These are slower than the definitions with lists. Go figure.
  285. ; (define-syntax collect-vector
  286. ; (syntax-rules ()
  287. ; ((COLLECT-VECTOR clause0 clause1+ ...)
  288. ; (%COLLECT-VECTOR
  289. ; (MAKE-VECTOR VECTOR-LENGTH VECTOR-SET! IN-VECTOR)
  290. ; DATUM
  291. ; () ;No check for the data.
  292. ; clause0 clause1+ ...))))
  293. ;
  294. ; (define-syntax collect-string
  295. ; (syntax-rules ()
  296. ; ((COLLECT-STRING clause0 clause1+ ...)
  297. ; (%COLLECT-VECTOR
  298. ; (MAKE-STRING STRING-LENGTH STRING-SET! IN-STRING)
  299. ; DATUM
  300. ; ((IF (NOT (CHAR? DATUM))
  301. ; (ERROR "Non-character in COLLECT-STRING:" DATUM)))
  302. ; clause0 clause1+ ...))))
  303. ;
  304. ; (define-syntax %collect-vector
  305. ; (syntax-rules ()
  306. ; ((%COLLECT-VECTOR
  307. ; (make-vector vector-length vector-set! in-vector)
  308. ; datum (check ...)
  309. ; clause0 clause1+ ...)
  310. ; (RECEIVE (LENGTH CHUNK-INDEX CHUNK CHUNKS)
  311. ; (ITERATE ((LENGTH 0)
  312. ; (CHUNK-INDEX 0)
  313. ; (CHUNK (make-vector #x10))
  314. ; (CHUNKS '()))
  315. ; (LAMBDA (datum LENGTH CHUNK-INDEX CHUNK CHUNKS)
  316. ; check ...
  317. ; (LET ((CHUNK-LENGTH (vector-length CHUNK)))
  318. ; (IF (< CHUNK-INDEX CHUNK-LENGTH)
  319. ; (BEGIN
  320. ; (vector-set! CHUNK CHUNK-INDEX datum)
  321. ; (VALUES LENGTH
  322. ; (+ CHUNK-INDEX 1)
  323. ; CHUNK
  324. ; CHUNKS))
  325. ; (LET ((CHUNK*
  326. ; (make-vector
  327. ; (IF (>= CHUNK-LENGTH #x1000)
  328. ; #x1000
  329. ; (* CHUNK-LENGTH 2)))))
  330. ; (vector-set! CHUNK* 0 datum)
  331. ; (VALUES (+ LENGTH CHUNK-LENGTH)
  332. ; 1 ;We filled in the first slot,
  333. ; CHUNK* ; so start at index 1.
  334. ; (CONS CHUNK CHUNKS))))))
  335. ; clause0 clause1+ ...)
  336. ; (LET* ((TOTAL-LENGTH (+ LENGTH CHUNK-INDEX))
  337. ; (RESULT (make-vector TOTAL-LENGTH)))
  338. ; (LOOP ((FOR ELEMENT OFFSET (in-vector CHUNK 0 CHUNK-INDEX)))
  339. ; (vector-set! RESULT (+ LENGTH OFFSET) ELEMENT))
  340. ; (LOOP ((FOR CHUNK (IN-LIST CHUNKS))
  341. ; (WITH BASE LENGTH BASE*)
  342. ; (LET BASE* (- BASE (vector-length CHUNK))))
  343. ; (LOOP ((FOR ELEMENT OFFSET (in-vector CHUNK)))
  344. ; (vector-set! RESULT (+ BASE* OFFSET) ELEMENT)))
  345. ; RESULT)))))
  346. ;;;;; Non-reentrant Vector and String Collection
  347. ;;; For the following definitions, we defer the responsibility of
  348. ;;; bounds checking and error signalling to VECTOR-SET! and
  349. ;;; STRING-SET!. This may not be a good idea.
  350. (define-syntax collect-into-vector!
  351. (syntax-rules (FROM)
  352. ((COLLECT-INTO-VECTOR! vector-expression (FROM start-expression)
  353. clause0 clause1+ ...)
  354. (LET ((VECTOR vector-expression)
  355. (START start-expression))
  356. (ITERATE* ((INDEX start))
  357. (LAMBDA (BODY CONTINUATION)
  358. (VECTOR-SET! VECTOR INDEX (BODY))
  359. (CONTINUATION (+ INDEX 1)))
  360. clause0 clause1+ ...)))
  361. ((COLLECT-INTO-VECTOR! vector-expression clause0 clause1+ ...)
  362. (COLLECT-INTO-VECTOR! vector-expression (FROM 0) clause0 clause1+ ...))))
  363. (define-syntax collect-into-string!
  364. (syntax-rules (FROM)
  365. ((COLLECT-INTO-STRING! string-expression (FROM start-expression)
  366. clause0 clause1+ ...)
  367. (LET ((STRING string-expression)
  368. (START start-expression))
  369. (ITERATE* ((INDEX start))
  370. (LAMBDA (BODY CONTINUATION)
  371. (STRING-SET! STRING INDEX (BODY))
  372. (CONTINUATION (+ INDEX 1)))
  373. clause0 clause1+ ...)))
  374. ((COLLECT-INTO-STRING! string-expression clause0 clause1+ ...)
  375. (COLLECT-INTO-STRING! string-expression (FROM 0) clause0 clause1+ ...))))
  376. ;;; These should probably have bang suffixes to emphasize that they are
  377. ;;; non-reentrant.
  378. (define-syntax collect-vector-of-length
  379. (syntax-rules ()
  380. ((COLLECT-VECTOR-OF-LENGTH length clause0 clause1+ ...)
  381. (LET ((VECTOR (MAKE-VECTOR length)))
  382. (COLLECT-INTO-VECTOR! VECTOR clause0 clause1+ ...)
  383. VECTOR))))
  384. (define-syntax collect-string-of-length
  385. (syntax-rules ()
  386. ((COLLECT-STRING-OF-LENGTH length clause0 clause1+ ...)
  387. (LET ((STRING (MAKE-STRING length)))
  388. (COLLECT-INTO-STRING! STRING clause0 clause1+ ...)
  389. STRING))))
  390. ;;;; Numerical Collection
  391. (define-syntax collect-sum
  392. (syntax-rules (INITIAL)
  393. ((COLLECT-SUM (INITIAL value-expression) clause0 clause1+ ...)
  394. (ITERATE ((SUM value-expression)) + clause0 clause1+ ...))
  395. ((COLLECT-SUM clause0 clause1+ ...)
  396. (COLLECT-SUM (INITIAL 0) clause0 clause1+ ...))))
  397. (define-syntax collect-product
  398. (syntax-rules (INITIAL)
  399. ((COLLECT-PRODUCT (INITIAL value-expression) clause0 clause1+ ...)
  400. (ITERATE ((PRODUCT value-expression)) * clause0 clause1+ ...))
  401. ((COLLECT-PRODUCT clause0 clause1+ ...)
  402. (COLLECT-PRODUCT (INITIAL 1) clause0 clause1+ ...))))
  403. (define-syntax collect-count
  404. (syntax-rules ()
  405. ((COLLECT-COUNT clause0 clause1+ ...)
  406. (COLLECT-SUM clause0 clause1+ ... 1))))
  407. (define-syntax collect-average
  408. (syntax-rules ()
  409. ((COLLECT-AVERAGE clause0 clause1+ ...)
  410. (RECEIVE (SUM COUNT)
  411. (ITERATE* ((SUM 0) (COUNT 0))
  412. (LAMBDA (BODY CONTINUATION)
  413. (CONTINUATION (+ SUM (BODY)) (+ COUNT 1)))
  414. clause0 clause1+ ...)
  415. (/ SUM COUNT)))))
  416. ;;;; Collecting Extrema
  417. (define-syntax collect-extremum
  418. (syntax-rules (INITIAL)
  419. ((COLLECT-EXTREMUM comparator-expression (INITIAL initial-expression)
  420. clause0 clause1+ ...)
  421. (LET ((COMPARATOR comparator-expression))
  422. (ITERATE ((EXTREMUM initial-expression))
  423. (LAMBDA (DATUM EXTREMUM)
  424. (IF (COMPARATOR DATUM EXTREMUM) DATUM EXTREMUM))
  425. clause0 clause1+ ...)))
  426. ((COLLECT-EXTREMUM comparator-expression clause0 clause1+ ...)
  427. (LET ((COMPARATOR comparator-expression))
  428. (ITERATE ((EXTREMUM #F))
  429. (LAMBDA (DATUM EXTREMUM)
  430. (IF (AND DATUM EXTREMUM)
  431. (IF (COMPARATOR DATUM EXTREMUM) DATUM EXTREMUM)
  432. (OR DATUM EXTREMUM)))
  433. clause0 clause1+ ...)))))
  434. (define-syntax collect-minimum
  435. (syntax-rules (INITIAL)
  436. ((COLLECT-MINIMUM (INITIAL initial-expression) clause0 clause1+ ...)
  437. (ITERATE ((MINIMUM initial-expression)) MIN clause0 clause1+ ...))
  438. ((COLLECT-MINIMUM clause0 clause1+ ...)
  439. (ITERATE ((MINIMUM #F))
  440. (LAMBDA (DATUM MINIMUM)
  441. (IF (AND DATUM MINIMUM)
  442. (MIN DATUM MINIMUM)
  443. (OR DATUM MINIMUM)))
  444. clause0 clause1+ ...))))
  445. (define-syntax collect-maximum
  446. (syntax-rules (INITIAL)
  447. ((COLLECT-MAXIMUM (INITIAL initial-expression) clause0 clause1+ ...)
  448. (ITERATE ((MAXIMUM initial-expression)) MAX clause0 clause1+ ...))
  449. ((COLLECT-MAXIMUM clause0 clause1+ ...)
  450. (ITERATE ((MAXIMUM #F))
  451. (LAMBDA (DATUM MAXIMUM)
  452. (IF (AND DATUM MAXIMUM)
  453. (MAX DATUM MAXIMUM)
  454. (OR DATUM MAXIMUM)))
  455. clause0 clause1+ ...))))
  456. ;;;;; Generalization by Multiple Values
  457. (define-syntax collect-extremum*
  458. (syntax-rules (INITIAL)
  459. ((COLLECT-EXTREMUM* comparator-expression
  460. (INITIAL key-expression element-expression)
  461. clause0 clause1+ ...)
  462. (LET ((COMPARATOR comparator-expression)
  463. (INITIAL-KEY key-expression)
  464. (INITIAL-ELEMENT element-expression))
  465. (ITERATE* ((EXTREME-KEY INITIAL-KEY)
  466. (EXTREME-ELEMENT INITIAL-ELEMENT))
  467. (LAMBDA (BODY CONTINUATION)
  468. (RECEIVE (KEY ELEMENT) (BODY)
  469. (IF (COMPARATOR KEY EXTREME-KEY)
  470. (CONTINUATION KEY ELEMENT)
  471. (CONTINUATION EXTREME-KEY EXTREME-ELEMENT))))
  472. clause0 clause1+ ...)))
  473. ((COLLECT-EXTREMUM* comparator-expression clause0 clause1+ ...)
  474. (LET ((COMPARATOR comparator-expression))
  475. (ITERATE* ((EXTREME-KEY #F)
  476. (EXTREME-ELEMENT #F))
  477. (LAMBDA (BODY CONTINUATION)
  478. (RECEIVE (KEY ELEMENT) (BODY)
  479. (IF KEY
  480. (IF EXTREME-KEY
  481. (IF (COMPARATOR KEY EXTREME-KEY)
  482. (CONTINUATION KEY ELEMENT)
  483. (CONTINUATION EXTREME-KEY EXTREME-ELEMENT))
  484. (CONTINUATION KEY ELEMENT))
  485. (CONTINUATION EXTREME-KEY EXTREME-ELEMENT))))
  486. clause0 clause1+ ...)))))
  487. (define-syntax collect-minimum*
  488. (syntax-rules (INITIAL)
  489. ((COLLECT-MINIMUM* (INITIAL key-expression element-expression)
  490. clause0 clause1+ ...)
  491. (COLLECT-EXTREMUM* < (INITIAL key-expression element-expression)
  492. clause0 clause1+ ...))
  493. ((COLLECT-MINIMUM* clause0 clause1+ ...)
  494. (COLLECT-EXTREMUM* < clause0 clause1+ ...))))
  495. (define-syntax collect-maximum*
  496. (syntax-rules (INITIAL)
  497. ((COLLECT-MAXIMUM* (INITIAL key-expression element-expression)
  498. clause0 clause1+ ...)
  499. (COLLECT-EXTREMUM* < (INITIAL key-expression element-expression)
  500. clause0 clause1+ ...))
  501. ((COLLECT-MAXIMUM* clause0 clause1+ ...)
  502. (COLLECT-EXTREMUM* < clause0 clause1+ ...))))
  503. ;;;;; Generalization by Selectors
  504. (define-syntax collect-extremum-by
  505. (syntax-rules (INITIAL)
  506. ((COLLECT-EXTREMUM-BY comparator-expression selector-expression
  507. (INITIAL initial-expression)
  508. clause0 clause1+ ...)
  509. (LET ((COMPARATOR comparator-expression)
  510. (SELECTOR selector-expression)
  511. (INITIAL-ELEMENT initial-expression))
  512. (ITERATE* ((EXTREME-KEY (SELECTOR INITIAL-ELEMENT))
  513. (EXTREME-ELEMENT INITIAL-ELEMENT))
  514. => EXTREME-ELEMENT
  515. (LAMBDA (BODY CONTINUATION)
  516. (LET* ((ELEMENT (BODY))
  517. (KEY (SELECTOR ELEMENT)))
  518. (IF (COMPARATOR KEY EXTREME-KEY)
  519. (CONTINUATION KEY ELEMENT)
  520. (CONTINUATION EXTREME-KEY EXTREME-ELEMENT))))
  521. clause0 clause1+ ...)))
  522. ((COLLECT-EXTREMUM-BY comparator-expression selector-expression
  523. clause0 clause1+ ...)
  524. (LET ((COMPARATOR comparator-expression)
  525. (SELECTOR selector-expression))
  526. (ITERATE* ((EXTREME-KEY #F) (EXTREME-ELEMENT #F))
  527. => EXTREME-ELEMENT
  528. (LAMBDA (BODY CONTINUATION)
  529. (LET* ((ELEMENT (BODY))
  530. (KEY (SELECTOR ELEMENT)))
  531. (IF KEY
  532. (IF EXTREME-KEY
  533. (IF (COMPARATOR KEY EXTREME-KEY)
  534. (CONTINUATION KEY ELEMENT)
  535. (CONTINUATION EXTREME-KEY EXTREME-ELEMENT))
  536. (CONTINUATION KEY ELEMENT))
  537. (CONTINUATION EXTREME-KEY EXTREME-ELEMENT))))
  538. clause0 clause1+ ...)))))
  539. (define-syntax collect-minimum-by
  540. (syntax-rules (INITIAL)
  541. ((COLLECT-MINIMUM-BY selector-expression (INITIAL initial-expression)
  542. clause0 clause1+ ...)
  543. (COLLECT-EXTREMUM-BY < selector-expression (INITIAL initial-expression)
  544. clause0 clause1+ ...))
  545. ((COLLECT-MINIMUM-BY selector-expression clause0 clause1+ ...)
  546. (COLLECT-EXTREMUM-BY < selector-expression clause0 clause1+ ...))))
  547. (define-syntax collect-maximum-by
  548. (syntax-rules (INITIAL)
  549. ((COLLECT-MAXIMUM-BY selector-expression (INITIAL initial-expression)
  550. clause0 clause1+ ...)
  551. (COLLECT-EXTREMUM-BY > selector-expression (INITIAL initial-expression)
  552. clause0 clause1+ ...))
  553. ((COLLECT-MAXIMUM-BY selector-expression clause0 clause1+ ...)
  554. (COLLECT-EXTREMUM-BY > selector-expression clause0 clause1+ ...))))
  555. ;;;; Miscellaneous
  556. ;;; COLLECT-FIRST and COLLECT-OR work nicely. COLLECT-LAST and
  557. ;;; COLLECT-AND have the unfortunate property that the final expression
  558. ;;; is not evaluated in a tail position, which is very hard to arrange
  559. ;;; in the general case. For example, compare these two definitions of
  560. ;;; (a reduced version of) EVERY from SRFI 1:
  561. ;;;
  562. ;;; (define (every predicate list)
  563. ;;; (and (pair? list)
  564. ;;; (let loop ((list list))
  565. ;;; (let ((tail (cdr list)))
  566. ;;; (if (pair? tail)
  567. ;;; (and (predicate (car list))
  568. ;;; (loop tail))
  569. ;;; (predicate (car list)))))))
  570. ;;;
  571. ;;; (define (every predicate list)
  572. ;;; (collect-and (for element (in-list list))
  573. ;;; (predicate element)))
  574. ;;;
  575. ;;; The first definition duplicates the call to PREDICATE so that the
  576. ;;; last is in a tail position. COLLECT-AND cannot do this.
  577. (define-syntax collect-first
  578. (syntax-rules (DEFAULT)
  579. ((COLLECT-FIRST (DEFAULT default-expression) clause0 clause1+ ...)
  580. (NESTED-LOOP (LAMBDA () default-expression)
  581. () ;No state
  582. (LAMBDA (BODY CONTINUATION)
  583. CONTINUATION ;ignore
  584. (BODY))
  585. clause0 clause1+ ...))
  586. ((COLLECT-FIRST clause0 clause1+ ...)
  587. (COLLECT-FIRST (DEFAULT (ERROR "Nothing generated in COLLECT-FIRST."))
  588. clause0 clause1+ ...))))
  589. (define-syntax collect-last
  590. (syntax-rules (DEFAULT)
  591. ((COLLECT-LAST (DEFAULT default-expression) clause0 clause1+ ...)
  592. (NESTED-LOOP (LAMBDA (RESULT) RESULT)
  593. ((RESULT default-expression))
  594. (LAMBDA (BODY CONTINUATION) (CONTINUATION (BODY)))
  595. clause0 clause1+ ...))))
  596. (define-syntax collect-or
  597. (syntax-rules ()
  598. ((COLLECT-OR clause0 clause1+ ...)
  599. (NESTED-LOOP (LAMBDA () #F)
  600. () ;No state
  601. (LAMBDA (BODY CONTINUATION) (OR (BODY) (CONTINUATION)))
  602. clause0 clause1+ ...))))
  603. (define-syntax collect-and
  604. (syntax-rules ()
  605. ((COLLECT-AND clause0 clause1+ ...)
  606. (NESTED-LOOP (LAMBDA (RESULT) RESULT)
  607. ((RESULT #F))
  608. (LAMBDA (BODY CONTINUATION)
  609. (LET ((RESULT (BODY))) (AND RESULT (CONTINUATION RESULT))))
  610. clause0 clause1+ ...))))