loop.texi 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. @node Macros for writing loops
  2. @section Macros for writing loops
  3. @i{(This section was derived from work copyrighted @copyright{}
  4. 1993--2005 by Richard Kelsey, Jonathan Rees, and Mike Sperber.)}
  5. @texonlyindent
  6. @stindex reduce
  7. @code{Iterate} & @code{reduce} are extensions of named-@code{let} for
  8. writing loops that walk down one or more sequences, such as the
  9. elements of a list or vector, the characters read from a port, or an
  10. arithmetic series. Additional sequences can be defined by the user.
  11. @code{Iterate} & @code{reduce} are exported by the structure
  12. @code{reduce}.
  13. @menu
  14. * Main looping macros::
  15. * Sequence types::
  16. * Synchronous sequences::
  17. * Examples::
  18. * Defining sequence types::
  19. * Loop macro expansion::
  20. @end menu
  21. @node Main looping macros
  22. @subsection Main looping macros
  23. @deffn syntax iterate
  24. @lisp
  25. (iterate @var{loop-name} ((@var{seq-type} @var{elt-var} @var{arg} @dots{})
  26. @dots{})
  27. ((@var{state-var} @var{init})
  28. @dots{})
  29. @var{body}
  30. [@var{tail-exp}])@end lisp
  31. @code{Iterate} steps the @var{elt-var}s in parallel through the
  32. sequences, while each @var{state-var} has the corresponding @var{init}
  33. for the first iteration and later values supplied by the body. If any
  34. sequence has reached the limit, the value of the @code{iterate}
  35. expression is the value of @var{tail-exp}, if present, or the current
  36. values of the @var{state-var}s, returned as multiple values. If no
  37. sequence has reached its limit, @var{body} is evaluated and either
  38. calls @var{loop-name} with new values for the @var{state-var}s or
  39. returns some other value(s).
  40. The @var{loop-name} and the @var{state-var}s & @var{init}s behave
  41. exactly as in named-@code{let}, in that @var{loop-name} is bound only
  42. in the scope of @var{body}, and each @var{init} is evaluated parallel
  43. in the enclosing scope of the whole expression. Also, the arguments
  44. to the sequence constructors will be evaluated in the enclosing scope
  45. of the whole expression, or in an extension of that scope peculiar to
  46. the sequence type. The named-@code{let} expression
  47. @lisp
  48. (let @var{loop-name} ((@var{state-var} @var{init}) @dots{})
  49. @var{body}
  50. @dots{})@end lisp
  51. @noindent
  52. is equivalent to an iterate expression with no sequences (and with an
  53. explicit @code{let} wrapped around the body expressions to take care of
  54. any internal definitions):
  55. @lisp
  56. (iterate @var{loop-name} ()
  57. ((@var{state-var} @var{init}) @dots{})
  58. (let () @var{body} @dots{}))@end lisp
  59. The @var{seq-type}s are keywords (actually, macros of a particular
  60. form, which makes it easy to add additional types of sequences; see
  61. below). Examples are @code{list*}, which walks down the elements of a
  62. list, and @code{vector*}, which does the same for vectors. For each
  63. iteration, each @var{elt-var} is bound to the next element of the
  64. sequence. The @var{arg}s are supplied to the sequence processors as
  65. other inputs, such as the list or vector to walk down.
  66. If there is a @var{tail-exp}, it is evaluated when the end of one or
  67. more sequences is reached. If the body does not call @var{loop-name},
  68. however, the @var{tail-exp} is not evaluated. Unlike named-@code{let},
  69. the behaviour of a non-tail-recursive call to @var{loop-name} is
  70. unspecified, because iterating down a sequence may involve side
  71. effects, such as reading characters from a port.
  72. @end deffn
  73. @deffn syntax reduce
  74. @lisp
  75. (reduce ((@var{seq-type} @var{elt-var} @var{arg} @dots{})
  76. @dots{})
  77. ((@var{state-var} @var{init})
  78. @dots{})
  79. @var{body}
  80. [@var{tail-exp}])@end lisp
  81. If an @code{iterate} expression is not meant to terminate before a
  82. sequence has reached its end, the body will always end with a tail call
  83. to @var{loop-name}. @code{Reduce} is a convenient macro that makes
  84. this common case explicit. The syntax of @code{reduce} is the same as
  85. that of @code{iterate}, except that there is no @var{loop-name}, and
  86. the body updates the state variables by returning multiple values in
  87. the stead of passing the new values to @var{loop-name}: the body must
  88. return as many values as there are state variables. By special
  89. dispension, if there are no state variables, then the body may return
  90. any number of values, all of which are ignored.
  91. The value(s) returned by an instance of @code{reduce} is (are) the
  92. value(s) returned by the @var{tail-exp}, if present, or the current
  93. value(s) of the state variables when the end of one or more sequences
  94. is reached.
  95. A @code{reduce} expression can be rewritten as an equivalent
  96. @code{iterate} expression by adding a @var{loop-name} and a wrapper for
  97. the body that calls the @var{loop-name}:
  98. @lisp
  99. (iterate loop ((@var{seq-type} @var{elt-var} @var{arg} @dots{})
  100. @dots{})
  101. ((@var{state-var} @var{init})
  102. @dots{})
  103. (call-with-values (lambda () @var{body})
  104. loop)
  105. [@var{tail-exp}])@end lisp
  106. @end deffn
  107. @node Sequence types
  108. @subsection Sequence types
  109. @deffn {sequence type} list* elt-var list
  110. @deffnx {sequence type} vector* elt-var vector
  111. @deffnx {sequence type} string* elt-var string
  112. @deffnx {sequence type} count* elt-var start [end [step]]
  113. @deffnx {sequence type} input* elt-var input-port reader-proc
  114. @deffnx {sequence type} stream* elt-var proc initial-seed
  115. For lists, vectors, & strings, the @var{elt-var} is bound to the
  116. successive elements of the list or vector, or the successive characters
  117. of the string.
  118. For @code{count*}, the @var{elt-var} is bound to the elements of the
  119. sequence @code{start, start + step, start + 2*step, @dots{}, end},
  120. inclusive of @var{start} and exclusive of @var{end}. The default
  121. @var{step} is @code{1}, and the sequence does not terminate if no
  122. @var{end} is given or if there is no @var{N} > 0 such that @var{end} =
  123. @var{start} + @var{N}@var{step}. (@code{=} is used to test for
  124. termination.) For example, @code{(count* i 0 -1)} does not terminate
  125. because it begins past the @var{end} value, and @code{(count* i 0 1 2)}
  126. does not terminate because it skips over the @var{end} value.
  127. For @code{input*}, the elements are the results of successive
  128. applications of @var{reader-proc} to @var{input-port}. The sequence
  129. ends when the @var{reader-proc} returns an end-of-file object, @ie{}
  130. a value that satisfies @code{eof-object?}.
  131. For @code{stream*}, the @var{proc} receives the current seed as an
  132. argument and must return two values, the next value of the sequence &
  133. the next seed. If the new seed is @code{#f}, then the previous element
  134. was the last one. For example, @code{(list* elt list)} is the same as
  135. @lisp
  136. (stream* elt
  137. (lambda (list)
  138. (if (null? list)
  139. (values 'ignored #f)
  140. (values (car list) (cdr list))))
  141. list)@end lisp
  142. @end deffn
  143. @node Synchronous sequences
  144. @subsection Synchronous sequences
  145. When using the sequence types described above, a loop terminates when
  146. any of its sequences terminate. To help detect bugs, it is useful to
  147. also have sequence types that check whether two or more sequences end
  148. on the same iteration. For this purpose, there is a second set of
  149. sequence types called @dfn{synchronous sequences}. Synchronous
  150. sequences are like ordinary asynchronous sequences in every respect
  151. except that they cause an error to be signalled if a loop is terminated
  152. by a synchronous sequence and some other synchronous sequence did not
  153. reach its end on the same iteration.
  154. Sequences are checked for termination in order from left to right, and
  155. if a loop is terminated by an asynchronous sequence no further checking
  156. is done.
  157. @deffn {synchronous sequence type} list% elt-var list
  158. @deffnx {synchronous sequence type} vector% elt-var vector
  159. @deffnx {synchronous sequence type} string% elt-var string
  160. @deffnx {synchronous sequence type} count% elt-var start end [step]
  161. @deffnx {synchronous sequence type} input% elt-var input-port reader-proc
  162. @deffnx {synchronous sequence type} stream% elt-var proc initial-seed
  163. These are all identical to their asynchronous equivalents above, except
  164. that they are synchronous. Note that @code{count%}'s @var{end}
  165. argument is required, unlike @code{count*}'s, because it would be
  166. nonsensical to check for termination of a sequence that does not
  167. terminate.
  168. @end deffn
  169. @node Examples
  170. @subsection Examples
  171. Gathering the indices of list elements that answer true to some
  172. predicate.
  173. @lisp
  174. (define (select-matching-items list pred)
  175. (reduce ((list* elt list)
  176. (count* i 0))
  177. ((hits '()))
  178. (if (pred elt)
  179. (cons i hits)
  180. hits)
  181. (reverse hits)))@end lisp
  182. Finding the index of an element of a list that satisfies a predicate.
  183. @lisp
  184. (define (find-matching-item list pred)
  185. (iterate loop ((list* elt list)
  186. (count* i 0))
  187. () ; no state variables
  188. (if (pred elt)
  189. i
  190. (loop))))@end lisp
  191. Reading one line of text from an input port.
  192. @lisp
  193. (define (read-line port)
  194. (iterate loop ((input* c port read-char))
  195. ((chars '()))
  196. (if (char=? c #\newline)
  197. (list->string (reverse chars))
  198. (loop (cons c chars)))
  199. (if (null? chars)
  200. (eof-object) ; from the PRIMITIVES structure
  201. (list->string (reverse chars)))))@end lisp
  202. Counting the lines in a file. This must be written in a way other than
  203. with @code{count*} because it needs the value of the count after the
  204. loop has finished, but the count variable would not be bound then.
  205. @lisp
  206. (define (line-count filename)
  207. (call-with-input-file filename
  208. (lambda (inport)
  209. (reduce ((input* line inport read-line))
  210. ((count 0))
  211. (+ count 1)))))@end lisp
  212. @node Defining sequence types
  213. @subsection Defining sequence types
  214. The sequence types are object-oriented macros similar to enumerations.
  215. An asynchronous sequence macro needs to supply three values: @code{#f}
  216. to indicate that it is not synchronous, a list of state variables and
  217. their initializers, and the code for one iteration. The first two
  218. methods are written in continuation-passing style: they take another
  219. macro and argument to which to pass their result. See [Friedman 00]
  220. for more details on the theory behind how CPS macros work. The
  221. @code{sync} method receives no extra arguments. The @code{state-vars}
  222. method is passed a list of names that will be bound to the arguments of
  223. the sequence. The final method, for stepping the sequence forward, is
  224. passed the list of names bound to the arguments and the list of state
  225. variables. In addition, there is a variable to be bound to the next
  226. element of the sequence, the body expression for the loop, and an
  227. expression for terminating the loop.
  228. As an example, the definition of @code{list*} is:
  229. @lisp
  230. (define-syntax list*
  231. (syntax-rules (SYNC STATE-VARS STEP)
  232. ((LIST* SYNC (next more))
  233. (next #F more))
  234. ((LIST* STATE-VARS (start-list) (next more))
  235. (next ((list-var start-list)) more))
  236. ((LIST* STEP (start-list) (list-var) value-var loop-body tail-exp)
  237. (IF (NULL? list-var)
  238. tail-exp
  239. (LET ((value-var (CAR list-var))
  240. (list-var (CDR list-var)))
  241. loop-body)))))@end lisp
  242. Synchronized sequences are similar, except that they need to provide a
  243. termination test to be used when some other synchronized method
  244. terminates the loop. To continue the example:
  245. @lisp
  246. (define-syntax list%
  247. (syntax-rules (SYNC DONE)
  248. ((LIST% SYNC (next more))
  249. (next #T more))
  250. ((LIST% DONE (start-list) (list-var))
  251. (NULL? list-var))
  252. ((LIST% . anything-else)
  253. (LIST* . anything-else))))@end lisp
  254. @node Loop macro expansion
  255. @subsection Loop macro expansion
  256. Here is an example of the expansion of the @code{reduce} macro:
  257. @lisp
  258. (reduce ((list* x '(1 2 3)))
  259. ((r '()))
  260. (cons x r))
  261. @expansion{}
  262. (let ((final (lambda (r) (values r)))
  263. (list '(1 2 3))
  264. (r '()))
  265. (let loop ((list list) (r r))
  266. (if (null? list)
  267. (final r)
  268. (let ((x (car list))
  269. (list (cdr list)))
  270. (let ((continue (lambda (r)
  271. (loop list r))))
  272. (continue (cons x r)))))))@end lisp
  273. The only mild inefficiencies in this code are the @code{final} &
  274. @code{continue} procedures, both of which could trivially be
  275. substituted in-line. The macro expander could easily perform the
  276. substitution for @code{continue} when there is no explicit proceed
  277. variable, as in this case, but not in general.