main.rkt
#lang scribble/lp

@(require scribble/eval
	  (for-label racket))

@CHUNK[<*>
       (require
	(for-syntax racket)
	(for-syntax "set-values.rkt")
	"set-values.rkt"
	 racket/generator)
       <define-end-of-generator>
       <local-macros>
       <supporting-functions>
       <return>
       <add-cond-clause>
       <make-hash-generator>
       <all-the-rest>
       (define (macroexpand-1 datum)
	 (syntax->datum (expand-once datum)))
       (provide macroexpand-1)
       ]

@section{Introduction}

This is an implementation of Common Lisp's LOOP macro for Racket. The LOOP macro is similar to all of Racket's for/* macros, combined with
Python's @scheme[for] loop, except it's more powerful than either.

Examples:

@racketblock[
	     (define (sift pred? list)
	       (loop for value in list
		     when (pred? value) consing value into gold
		     else consing value into dirt
		     finally (return (values (reverse gold) (reverse dirt)))))
]

@racketinput[(loop for x in '(a b c d e f g)
		   for y from 0
		   when (even? y)
		   collect x)]

 @racketresult[(a c e g)]


@racketinput[(loop for x in '(a b c d e f g)
		   for y in '(1 2 3 4 5 6 7)
		   with-collection-type hash
		   collect (cons x y))]

 @racketresult[ #hash((c . 3) (f . 6) (g . 7) (e . 5) (d . 4) (a . 1) (b . 2)) ]

LOOP can also do the job of @scheme[for/and]:

@racketblock[(loop for x in a-list
		   for y in another-list always (and (number? x)
						     (symbol? y)))]

...or @scheme[for/or]:

@racketblock[(loop for x in a-list thereis (symbol? x))]

...or @scheme[for/sum]:

@racketblock[(loop for x in a-list when (integer? (sqrt x)) sum x)]

...or you can convert a list into a hash table:

@racketblock[(loop with collection-type 'hash/immutable
		    for key-value in '((key . val) (key2 . val2))
		    collect key-value)]

...or you can write an old-fashioned while loop:

@racketblock[(loop for line = (read-line socket)
		   while (not (eof-object? line))
		   do
		     (display line)
		     (newline)
		   finally
		     (close-input-port socket))]

The loop macro can also iterate over generators as defined in the  @scheme[racket/generator] package.

@racketblock[(loop for item in (gen)
		   do
		     (displayln item))]

Since @scheme[racket/generator] provides no non-ambiguous way to end a generator, arrange for your generator
to yield the value @scheme[end-of-generator] to terminate the loop, or use an explicit @scheme[return] clause
to exit.

@CHUNK[<define-end-of-generator>
       (define-struct end-of-generator* ())
       (define end-of-generator (make-end-of-generator*))
       (define end-of-generator? end-of-generator*?)
       (provide end-of-generator end-of-generator?)
       ]

@section{Enabling @scheme[return]}

In Common Lisp, the LOOP macro is often used in conjunction with @scheme[return] and @scheme[return-from]. Racket makes it extremely
difficult to make identifiers be implicitly bound within a given code block. Instead, this library defines @scheme[return] as a macro
which invokes a continuation that can be tucked away within this module.

@scheme[return] is defined as a macro and not a function because in Common Lisp, it's legal to do this:

@racketblock[
	     (return (values 1 2 3 4))
	     ]

...where Racket would tend to discourage this. @italic{return} and its hidden continuation are defined as follows:

@CHUNK[<return>
       (define return-cc (make-parameter #f))
       
       (define-syntax return
	 (syntax-rules ()
	   ((_) (return (void)))
	   ((_ value-form)
	    (call-with-values (λ () value-form)
	      (λ all-values
		 (apply (return-cc) all-values))))))
       (define-syntax return-from
	 (syntax-rules ()
	   ((_ block-name value-form)
	    (parameterize ((return-cc block-name))
	       (return value-form)))))
       (provide return return-from)
]

When the LOOP macro is invoked, it sets the @racketresult[return-cc] parameter with its own continuation, which is only an escape continuation.

@section{The Main Body}

@subsection{Variables That Hold Various Sections of Generated Code}

The main body of the macro iterates over all the clauses and builds the following variables:

@itemlist[ @item{@scheme[finally] is the @scheme[finally] clause, which gets executed after everything else, including the @scheme[return] clause.
			It does not affect the return value.}
	   @item{@scheme[iterations] is a syntax-list of all the variables that must be changed with each iteration of the loop, along with
			a snippet of code that does the change. An example of what might be in this variable is
			@scheme[#'((variable-name (add1 variable-name))
				   (var2 (cdr var2)))] The @scheme[iterations] get executed just as the loop is recursing into the next iteration}
	   @item{@scheme[current-condition] is a list of boolean clauses that is built while processing @scheme[if] clauses.}
	   @item{@scheme[loop-conditions] A syntax-list of conditions that will be combined with the @scheme[and]
			operator to determine if the loop should continue. These are checked just before the @scheme[iterations] are executed.}
	   
	   @item{@scheme[action-clauses] This is a list of action forms that will be combined with the @scheme[current-conditions] if they are
			defined, otherwise they go into the @scheme[body] naked.}
	   @item{@scheme[current-cond-body] This is a list of clauses for a @scheme[cond] form. This
			implements the @scheme[if] and @scheme[else], and @scheme[do] clauses of the loop. The @scheme[current-condition] gets added
			to this list along with code from one or more action clauses.}
	   @item{@scheme[body] is a collection of all action clauses and @scheme[current-cond-body]s to be executed. }
	   @item{@scheme[list-defs] are let-bindings for any lists that are being iterated over using a @scheme[for] clause. They are
			named with the @scheme[(gensym)] function.}
	   @item{@scheme[let-defs] are let-bindings for any variables bound with a @scheme[for] clause.}]

@subsection{Variables representing identifiers}

References to identifiers in the <loop-body> below need to be made from the code in the variables above, and this code is
generated outside of the scope of the <loop-body>. Because of Racket's hygienic macros, the only way to do this is to put
the identifiers themselves into variables that have a wider scope. Some of these identifiers are just the names of variables
within the @scheme[local-loop] block, but others may be changed during macro expansion:

@itemlist[ @item{@scheme[call-with-cc] determines the type of continuation that will be used. This was going to be used
			to implement a @scheme[yield] clause, which would change it from @scheme[call/ec] (the default)
			to @scheme[call/cc], but the @scheme[racket/generator] package already provides a @scheme[yield]
			form that can be used effectively from within the loop macro, so I'll save myself the headache
			of reinventing generators for Racket.}
	   @item{@scheme[initial-count], @scheme[initial-sum], @scheme[initial-string], and @scheme[initial-collection]
			are initial values for collector variables. They default to @scheme[#f] unless the relevant
			clause is used. The @scheme[#f] value is used to control the return value of the loop.}
	   ]

These variables can then be combined to form the loop itself, as it will eventually be expanded.:

@CHUNK[<loop-body>
       #`(let ((#,collection #,initial-collection)
	       (#,count* #,initial-count)
	       (#,sum* #,initial-sum)
	       (#,min #f)
	       (#,max #f)
	       (#,string-accumulator #,initial-string)
	       (#,reverse? #,reverse-value)
	       #,@let-defs
	       #,@list-defs)
	   (#,call-with-cc
	    (λ (#,return-continuation)
	       (parameterize
		((return-cc #,return-continuation))
		(gnarled-let-nest
		 #,gnarled-let-defs
		 (begin
		   #,@prologue
		   #,@initially-prologue
		   (let local-loop ()
		     (let-values
			 #,let-values-defs
		       #,@preiterations
		       (unless (and . #,loop-preconditions)
			       <exit-loop>)	
		       (begin . #,body)
		       (begin . #,<increment-lists>)
		       (begin . #,iterations)
		       (cond ((and . #,loop-conditions)
			      (local-loop))
			     (else
			      <exit-loop>))))))))))
    ]

@CHUNK[<exit-loop>
       (begin
	 #,@epilogue
	 (#,return-continuation (or <generate-collection-type> count sum (void))))
       ]

The @scheme[return-continuation] is used for all exits from the loop. 

All the lists being iterated over are handled separately from the recursion process. Each list has a corresponding variable that
is bound to the next element of the list via the @scheme[car] function. This binding is all that takes place during the
@scheme[iterations], and must happen after the lists themselves have been @scheme[cdr]'d off.

@CHUNK[<increment-lists>
       (let unroll-lists ((list-names (get-let-vars list-defs))
			  (result #'()))
	 (syntax-case list-names ()
	   (() result)
	   ((var . rest)
	    (unroll-lists #'rest #`((set! var (cdr var)) . #,result)))))
]

@section{Handling Conditional Statements}

Common Lisp's LOOP facility allows the use of @scheme[if] and @scheme[else] clauses that alter the behavior of the loop. Expansion of these
clauses proceeds as follows:

@itemlist[@item{ Rewrite all @scheme[when] clauses as @scheme[if] clauses }
	  @item{ Rewrite all @scheme[if foo and bar] as @scheme[if foo if bar] }
	  @item{ Collect all consecutive @scheme[if foo] clauses into @scheme[current-condition] }
	  @item{ If an action clause (such as @scheme[do], @scheme[collect], @scheme[count], etc) is encountered while a
		     @scheme[current-condition] exists, combine the action clause and the @scheme[current-condition] into
		     a clause that can be added to a @scheme[cond] form (@scheme[current-cond-body])@italic{.} The @scheme[and] operator
		     is added to the front of the @scheme[current-condition] list, unless @scheme[current-condition] is the word @scheme[else]@italic{.} }
	  @item{ After an action clause, an @scheme[else] clause can be encountered, which goes into the @scheme[current-condition],
		  ultimately adding another clause to the @scheme[current-cond-body] when an action clause is encountered. }
	  @item{ If an @scheme[end] clause is encountered, a @scheme[cond] statement is created with the @scheme[current-cond-body]
		     and added to the @scheme[body]@italic{.} }
	  @item{ If an @scheme[if] clause is encountered after @scheme[if condition action-clause ...], rewrite it as if it was preceded
		     by @scheme[end]@italic{.} }
	  #:style 'ordered ]

@subsection{Rewrite @scheme[when] and @scheme[unless] clauses}

The chunk of code below is evaluated within the context of a @scheme[syntax-case] macro called @scheme[loop-body].

@CHUNK[<rewrite-if-clauses>
       ((_ (when . rest))
	(parse-loop #`(loop-body (if . rest))))
       ((_ (unless condition . rest))
	(parse-loop #`(loop-body (if (not condition) . rest))))
       ((_ (else unless condition . rest))
	(parse-loop #`(loop-body (else if (not condition) . rest))))
]

@subsection{Collect consecutive @scheme[if] clauses}

@CHUNK[<collect-if-clauses>
       ((_ (if condition else . rest))
	(raise-syntax-error 'if-else "An action clause (such as do, collect, sum, etc) must occur between an if clause and an else clause"
			    #'(if condition else . rest)))
       ((_ (if condition . rest))
	(begin
	  (set! current-condition #`(condition . #,current-condition))
	  (set! and? #t)
	  (parse-loop #'(loop-body rest))))
       ]

@subsection{Collect @scheme[else] and @scheme[else if] clauses}

@CHUNK[<collect-else-if>       
       ((_ (else if condition . rest))
	(begin
	  (set! current-cond-body
		(add-cond-clause current-condition action-clauses current-cond-body))
	  (set! current-condition #`(condition))
	  (set! and? #t)
	  (set! action-clauses #'())
	  (parse-loop #'(loop-body rest))))
       ((_ (else . rest))
	(begin
	  (when (syntax-null? current-condition)
		(raise-syntax-error 'else "else must be preceded by an if, when, or unless followed by action clauses\r\nconnected with 'and'. Example: if condition do condition and collect something" stx))
	  (set! current-cond-body
		(add-cond-clause current-condition action-clauses current-cond-body))
	  (set! current-condition #'else)
	  (set! and? #t)
	  (set! action-clauses #'())
	  (parse-loop #'(loop-body rest))))
]       

@subsection{AND}

If AND appears after an action clause, then a subsequent action clause will be part of the previous conditional.

@CHUNK[<and>
((_ (and . rest))
 (begin
   (set! and? #t)
   (parse-loop #'(loop-body rest))))
]


@subsection{END}

The @scheme[end] clause denotes the end of conditional processing. Action clauses after this will
be treated as unconditional. Whatever @scheme[current-cond-body] is being built gets inserted
into the @scheme[body] at this point.

@CHUNK[<end>
	((_ (end . rest))
	 (begin
	   (when (and (syntax-null? current-condition)
		      (syntax-null? current-cond-body))
		 (raise-syntax-error 'end "end must be preceded by an if, when, or unless clause and an action clause." stx))
	   (set! and? #f)
	   (unless (syntax-null? current-condition)
		   (set! current-cond-body (add-cond-clause current-condition action-clauses current-cond-body))
		   (set! action-clauses #'())
		   (set! current-condition #'()))
	   (set! body #`(#,@body (cond . #,(syntax-reverse current-cond-body))))
	   (set! current-cond-body #'())
	   (parse-loop #'(loop-body rest))))
]

@CHUNK[<add-cond-clause>
(define-for-syntax (add-cond-clause condition cond-body current-cond-body)
  #`((#,(fix-current-condition condition)
      . #,cond-body) . #,current-cond-body))

(define-for-syntax (fix-current-condition condition)
  (if (syntax-null? condition)
      #'()
      (syntax-case condition (else)
	((hd . tl) #`(and . #,(syntax-reverse condition)))
	(else condition))))
]

@section{Action clauses}

The action clauses are where the @scheme[current-condition] gets combined with some code to add to a
@scheme[current-cond-body].

Most action clauses only accept one form as an argument, but the @scheme[do] clause is special. Any compound form
(ie, one surrounded by parentheses) following the @scheme[do] clause is part of the action clause, and a @scheme[do] without
an action clause is illegal. This means the @scheme[do] form cannot be processed by rewriting it into another @scheme[do] form.
Instead, it is rewritten as a @scheme[do-internal] form, which is ignored if the form following it is not a compound form.

@CHUNK[<do-clause>
       ((_ (do (hd . tl) (hd2 . tl2) . rest))
	(parse-loop #'(loop-body (do-internal (hd . tl) and do (hd2 . tl2) . rest))))
       ((_ (do (hd . tl) . rest))
	(parse-loop #'(loop-body (do-internal (hd . tl) . rest))))
       ((_ (do non-list . rest))
	(raise-syntax-error 'do "Missing compound-form after do" #'(do non-list . rest)))
]

@subsection{Unavoidable boilerplate}

There are various chores that each action clause must accomplish on its own. Unfortunately, macro hygiene makes it
impossible to define macros to do it. The macros must be defined in a separate file due to limitations in Racket,
and due to the hygiene, local variables here wouldn't be visible to the code generated by the macro.

One thing that each action clause must do is detect whether two action clauses have been written in a row,
which breaks the conditional. For example in the following code:

@racketblock[ (loop for x from 1 to 10 if (even? x) collect x do (displayln x)) ]

..the @scheme[do] clause should be interpreted as if it was preceded by an @scheme[end] clause. That is, the @scheme[cond] form
that goes with the @scheme[if] clause should be generated before generating the code that implements the @scheme[do] clause.
The check for whether this should be done is:

@CHUNK[<action-boilerplate-guard>
       (or and?
	   (syntax-null? current-condition))
]

The @italic{current-condition} is the boolean expression (missing its @italic{and} operator) that determines whether the
action-clause should be executed. If there is no @italic{current-condition}, then that means the action-clause being
processed should be executed unconditionally. But if even if there @italic{is} a @italic{current-condition}, it may
be a stale @italic{current-condition} left over from a previous action-clause. The @italic{current-condition} is only
fresh if the @italic{and?} flag is set.

Therefore, if the above expression is true, it is safe to go ahead and process the action clause, otherwise an @scheme[end] clause must
be inserted and processed first. The code to do the inserting varies between action clauses just enough to prevent it from being
put in a chunk.

After the action-clause needs no further preprocessing, the next thing that must happen is that some code must be generated. What
exactly is generated differs between each action-clause, but all action-clause generated code goes into a list, where it is later
either placed into a @scheme[cond] form, or added naked to the @italic{body}. 

The generated snippet of code is added with this function:

@CHUNK[<define-add-action-clause>
       (define (add-action-clause clause)
	 (set! action-clauses #`(#,@action-clauses #,clause)))
]


After adding its action-clause code to the @italic{action-clauses} using @scheme[add-action-clause], every action-clause
must check if the clause is conditional or not. If the clause is conditional (that is, if @italic{current-condition}
										   is non-empty),
then the @italic{action-clauses} are left alone for later processing, and the @italic{body} is not modified, as
this will be handled in the @italic{end} clause. But
if the action-clause is unconditional, its contents must be added to the @italic{body} now.

@CHUNK[<action-boilerplate>
       (when (syntax-null? current-condition)
	     (set! body #`(#,@body #,@action-clauses))
	     (set! action-clauses #'()))
       (set! and? #f)
]


@CHUNK[<do-internal>
       ((_ (do-internal (hd . tl) . rest))
	(begin
	(cond (<action-boilerplate-guard>
	       (add-action-clause #'(hd . tl))
	       <action-boilerplate>
	       (parse-loop #'(loop-body (do-internal . rest))))
	      (else
	       (parse-loop #'(loop-body (end do-internal (hd . tl) . rest)))))))
]

When @scheme[do-internal] runs out of compound forms, then everything is placed into the @scheme[body] using
the boilerplate code.

@CHUNK[<do-internal/2>
       ((_ (do-internal . rest))
	(parse-loop #'(loop-body  rest)))
       ]

@subsection{Other Action Clauses}

@subsubsection{@scheme[collect]}

The @scheme[collect] clause tells the loop to store a value in a collection list, which will
be returned.


@CHUNK[<collect-clause>
       <collect-into>
       ((_ (collect value . rest))
	(cond (<action-boilerplate-guard>
	       (set! initial-collection (syntax '()))
	       (add-action-clause #`(set! #,collection (cons value #,collection)))
	       <action-boilerplate>
	       (parse-loop #'(loop-body  rest)))
	      (else
	       (parse-loop #'(loop-body (end collect value . rest))))))
       ((_ (collecting value . rest))
	(parse-loop #'(loop-body (collect value . rest))))
]

The loop macro also supports collecting @italic{into} a specific variable.

@racketblock[ (loop for x in list when (odd? x) collect into odds) ]

Doing this requires a separate version of the above macro. It wasn't possible to combine the above's
functionality because there's no way to compare syntax-objects to tell if an identifier that appears
in the pattern equals @scheme[collection] or another macro variable.

Furthermore, because the collection variable can be accessed during iteration, and must be a list in the
correct order, it is not possible to cons the list in reverse order and then reverse it, as is done
with the implicit collector. Instead, adding to the end of the list is done with @scheme[append], which
makes @italic{collect into} O(n) for each iteration where a @italic{collect into} occurs. A loop that
uses @italic{collect into} on every iteration could be as slow as O(n@superscript{2}).

@CHUNK[<collect-into>
((_ (collect value into collector . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(set! collector (append collector (list value))))
	<action-boilerplate>
	(set! let-defs #`((collector '()) . #,let-defs))
	(parse-loop #'(loop-body  rest)))
       (else
	(parse-loop #'(loop-body (end collect value into collector . rest))))))       
]

@subsubsection{@scheme[cons]}

Because @italic{collect into} is such a uselessly pathological case in Racket (in contrast
with how useful it is in Common Lisp), an extension is provided: @scheme[cons into] operates like
@scheme[collect into], except the resulting list is seen in reverse order. There is no @scheme[cons]
without @scheme[into], and if there was, it'd be a synonym for @scheme[collect].

@CHUNK[<cons-into>
((_ (cons value into collector . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(set! collector (cons value collector)))
	<action-boilerplate>
	(set! let-defs #`((collector '()) . #,let-defs))
	(parse-loop #'(loop-body  rest)))
       (else
	(parse-loop #'(loop-body (end cons value into collector . rest))))))
((_ (consing . rest))
 (parse-loop #'(loop-body (cons . rest))))
]

@subsubsection{@scheme[collect] variants}

The @scheme[collect] clause can return different types. The return type is controlled by
the @scheme[collection-type] variable, which can be set using the @scheme[with-collection-type]
clause. When the loop is about to return, it checks the collection-type and constructs
a return value as follows:

@CHUNK[<generate-collection-type>
       (begin
	 (if #,collection
	     (case #,collection-type
	       ((list) (if #,reverse? (reverse #,collection)
			   #,collection))
	       ((vector) (list->vector (reverse #,collection)))
	       ((string) (list->string (reverse #,collection)))
	       ((bytes) (list->bytes (reverse #,collection)))
	       ((hash) (list->hash #,collection))
	       ((hash/immutable) (list->hash/immutable #,collection)))
	     #f))
       ]

That last two conversions are not provided by Racket. They must be implemented here.

@CHUNK[<list->hash>
       (define-syntax define-list->hash
	 (syntax-rules ()
	   ((_ list->hash hash-return make pair set)
	    (define (list->hash lst)
	      (call/ec
	       (λ (return)
		  (loop with hash-return = (make)
			for pair in lst
			do set
			finally (return hash-return))))))))
       (define-list->hash list->hash hash-return make-hash pair (hash-set! hash-return (car pair) (cdr pair)))
       (define-list->hash list->hash/immutable hash-return make-immutable-hash pair (set! hash-return
											  (hash-set hash-return (car pair) (cdr pair))))
      ]

@CHUNK[<with-collection-type>
((_ (with-collection-type type . rest))
 (begin
   (case (syntax->datum #'type)
     ((list) #t)
     ((vector) #t)
     ((string) #t)
     ((bytes) #t)
     ((hash) #t)
     ((hash/immutable) #t)
     (else (raise-syntax-error 'with-collection-type "Unsupported collection type" #'type)))
   (set! collection-type #`'type)
   (parse-loop #'(loop-body rest))))
]

@subsubsection{@scheme[append]}

This is like @scheme[collect], except the value must be a list, which will be appended to the
end of the collection.

@CHUNK[<append-clause>
((_ (append value into collector . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(set! collector (append collector value)))
	<action-boilerplate>
	(set! let-defs #`((collector '()) . #,let-defs))
	(parse-loop #'(loop-body  rest)))
       (else
	(parse-loop #'(loop-body (end append value into collector . rest))))))
((_ (append value . rest))
 (cond (<action-boilerplate-guard>
	(set! reverse-value #'#f)
	(set! initial-collection (syntax '()))
	(add-action-clause #`(set! #,collection (append #,collection value)))
	<action-boilerplate>
	(parse-loop #'(loop-body  rest)))
       (else
	(parse-loop #'(loop-body (end append value . rest))))))
((_ (appending . rest))
 (parse-loop #'(loop-body (append . rest))))
]

@subsubsection{@scheme[sum]}

This clause adds the given value to a numerical accumulator, which is then returned.

@CHUNK[<sum-clause>
((_ (sum value into collector . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(set! collector (+ collector value)))
	<action-boilerplate>
	(set! let-defs #`((collector 0) . #,let-defs))
	(parse-loop #'(loop-body  rest)))
       (else
	(parse-loop #'(loop-body (end sum value into collector . rest))))))
((_ (sum value . rest))
 (cond (<action-boilerplate-guard>
	(set! initial-sum #'0)
	(add-action-clause #`(set! #,sum* (+ #,sum* value)))
	<action-boilerplate>
	(parse-loop #'(loop-body rest)))
       (else
	(parse-loop #'(loop-body (end sum value . rest))))))
((_ (summing . rest))
 (parse-loop #'(loop-body sum . rest)))
]

@subsubsection{@scheme[count]}

Counts the number of times the expression evaluates as true. Due to a bug in Racket, it was
necessary to do some syntax-object manipulation to detect when the word @scheme[count] is passed
to the macro. This work around is the reason these syntax-case patterns say @scheme[_count] instead.

@CHUNK[<count-clause>
((_ (_count expression into collector . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(when expression
				   (set! collector (add1 collector))))
	<action-boilerplate>
	(set! let-defs #`((collector 0) . #,let-defs))
	(parse-loop #'(loop-body  rest)))
       (else
	(parse-loop #'(loop-body (end count expression into collector . rest))))))
((_ (_count expression . rest))
 (cond (<action-boilerplate-guard>
	(set! initial-count #'0)
	(add-action-clause #`(when expression
				   (set! #,count* (add1 count))))
	<action-boilerplate>
	(parse-loop #'(loop-body rest)))
       (else
	(parse-loop #'(loop-body end count expression . rest)))))
((_ (counting . rest))
 (parse-loop #'(loop-body (_count . rest))))
]

@subsubsection{@scheme[minimize and maximize]}

This binds the smallest random number seen into @scheme[min-random]:

@racketblock[ (loop repeat 100 minimizing (random 100) into min-random ...) ]

@CHUNK[<min/max>
((_ (minimize expression into collector . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(let ((temp expression))
			       (when (or (not collector)
					 (< temp collector))
				     (set! collector temp))))
	<action-boilerplate>
	(set! let-defs #`((collector #f) . #,let-defs))
	(parse-loop #'(loop-body  rest)))
       (else
	(parse-loop #'(loop-body (end count expression into collector . rest))))))
((_ (minimize expression . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(let ((temp expression))
			       (when (or (not min)
					 (< temp min))
				     (set! min temp))))
	<action-boilerplate>
	(parse-loop #'(loop-body rest)))
       (else
	(parse-loop #'(loop-body end count expression . rest)))))
((_ (minimizing . rest))
 (parse-loop #'(loop-body (minimize . rest))))

((_ (maximize expression into collector . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(let ((temp expression))
			       (when (or (not collector)
					 (> temp collector))
				     (set! collector temp))))
	<action-boilerplate>
	(set! let-defs #`((collector #f) . #,let-defs))
	(parse-loop #'(loop-body  rest)))
       (else
	(parse-loop #'(loop-body (end count expression into collector . rest))))))
((_ (maximize expression . rest))
 (cond (<action-boilerplate-guard>
	(add-action-clause #`(let ((temp expression))
			       (when (or (not max)
					 (> temp max))
				     (set! max temp))))
	<action-boilerplate>
	(parse-loop #'(loop-body rest)))
       (else
	(parse-loop #'(loop-body end count expression . rest)))))
((_ (maximizing . rest))
 (parse-loop #'(loop-body (maximize . rest))))
]


@section{While and Until}

@racketblock[ (loop while keep-going ...) ]

@racketblock[ (loop until stop ...) ]

@CHUNK[<while/until>
((_ (while condition . rest))
 (begin
   (set! loop-preconditions
	 #`(condition . #,loop-preconditions))
   (parse-loop #'(loop-body rest))))
((_ (until condition . rest))
 (parse-loop #'(loop-body (while (not condition) . rest))))
]

@section{Repeating a Set Number of Times}

@racketblock[ (loop repeat 15 collect 'ocd) ]

@racketresult[(ocd ocd ocd ocd ocd ocd ocd ocd ocd ocd ocd ocd ocd ocd ocd) ]

@CHUNK[<repeat>
((_ (repeat n . rest))
 (parse-loop #'(loop-body (for x from 1 to n . rest))))
]
@section{Iterating over stuff}

The @scheme[for] keyword denotes all forms of iteration:

@racketblock[
   (loop for variable preposition some-kind-of-collection ...)
]

In traditional Common Lisp, the @scheme[preposition] determines the type of @scheme[some-kind-of-collection]:

@itemlist[
   @item{@italic{in} to iterate over lists}
   @item{@italic{across} to iterate over arrays}
]

In Common Lisp, strings and vectors are both arrays, and Common Lisp has no equivalent to @scheme[bytes].

Common Lisp also provides the @scheme[on] preposition, which iterates over lists, except that the
@scheme[variable] is set to the entire remaining portion of the list instead of just the next element
in the list.

In this version of the loop macro, @scheme[across] iterates over vectors, strings, and bytes, while
@scheme[in] iterates over lists and hash tables, and @scheme[over] iterates over generators.


This version of the macro also iterates over hash-tables and generators.

All the variants of the for-clause can be captured by this @scheme[syntax-case] pattern:

@CHUNK[<universal-for-clause>
((_ (for . rest))
 (unless (and (syntax-null? current-condition)
	      (syntax-null? action-clauses)
	      (syntax-null? current-cond-body))
	 (raise-syntax-error 'loop "\"for\" must precede all \"if\", \"when\", \"collect\", and \"do\" clauses" stx))
 (syntax-case #'(for . rest) <loop-literals>
   <individual-for-clauses>
   (not-a-for-clause
    (parse-loop #'(loop-body not-a-for-clause)))))
]

The variations are all processed in a local @scheme[syntax-case] form.

@subsection{for x in y: List and Hash Iteration}

Iterating over lists is the most basic case. The @scheme[list-defs] let-bindings can hold a binding for the list @italic{y}, which
automatically results in the list being @italic{cdr}'d as the loop progresses, while
the iterator variable @italic{x} is part of the @scheme[let-defs]. Finally, @scheme[iterations] receives code that will update @italic{x}
with each loop iteration.

@CHUNK[<for-x-in-y>
<destructuring-for-x-in-y>
((for x in y . rest)
 (let ((y-binding (datum->syntax stx (gensym))))
   (set! iterations #`((set! x #f) (set! #,y-binding (cdr #,y-binding)). #,iterations))
   (set! preiterations #`(#,@preiterations (set! x (if (null? #,y-binding) #f
						       (car #,y-binding)))))
   (set! loop-preconditions #`((not (null? #,y-binding)) . #,loop-preconditions))
				 
   (set! loop-conditions #`((not (null? #,y-binding)) . #,loop-conditions))
   (parse-loop #`(loop-body (with #,y-binding = y with x = (if (null? #,y-binding)
							       #f
							       (car #,y-binding)) . rest)))))
]

Common Lisp also supports the following:

@racketblock[
  (loop for ((a b) (c d)) in '(((1 2) (3 4)) ((5 6) (7 8))) ...)
]

...where the elements in the lists can be destructured according to the pattern
@scheme[((a b) (c d))] to arbitrary depth. The variables can be bound using
Racket's old @scheme[mzlib/match], (but not the @scheme[racket/match], due to the
need to throw in the word @scheme[list] gratuitously). For some reason, you cannot
import @scheme[racket/mzlib] into a Scribble/LP program, due specifically to conflicts
between MzLib's match and Racket's match. This error doesn't occur under #@scheme[lang racket].
For this reason, a macro, @scheme[destructuring-bind], had to be defined in a separate file. @scheme[destructuring-bind]
is used exactly like its Common Lisp counterpart.

@CHUNK[<destructuring-for-x-in-y>
((for (x . rest-of-pattern) in y . rest)
 (let* ((y-binding (datum->syntax stx (gensym)))
	(variables <extract-variables-from-pattern>)
	(condition #`(not (null? #,y-binding))))
   (set! preiterations #`(#,@preiterations
			  (when #,condition
				(set-values! #,variables
					     (destructuring-bind (x . rest-of-pattern) (car #,y-binding)
								 (values . #,variables))))))
   (set! loop-preconditions #`(#,condition . #,loop-preconditions))
   (set! loop-conditions #`((not (null? #,y-binding)) . #,loop-conditions))
   (set! list-defs #`((#,y-binding y) . #,list-defs))
   (set! let-values-defs
	 #`((#,variables
	     (destructuring-bind (x . rest-of-pattern) (car #,y-binding)
				 (values . #,variables))) . #,let-values-defs))
   (parse-loop #'(loop-body rest))))
]

Before it becomes possible to bind variables specified in this pattern, it is necessary to flatten the
pattern into a plain list of variable names. This is used both in the let-values form, and in the return
value from the @scheme[match] pattern.

@CHUNK[<extract-variables-from-pattern>
(let loop ((pat #'(x . rest-of-pattern))
	   (result #'()))
    (syntax-case pat ()
      (() result)
      (((x . more-vars) . rest)
       (loop #'rest
	     (loop #'(x . more-vars)
		   result)))
      ((x . rest)
       (loop #'rest
	     #`(x . #,result)))))
]

@subsection{for x on y by iterator: List iteration with entire lists.}

@CHUNK[<for-x-on-y>
((for x on y by iter . rest)
 (let ((y-binding (datum->syntax stx (gensym)))
       (iter-binding (datum->syntax stx (gensym))))
   (set! iterations #`((set! x #f) (set! #,y-binding (#,iter-binding #,y-binding))
		       . #,iterations))
   (set! preiterations #`(#,@preiterations (set! x #,y-binding)))
   (set! loop-preconditions #`((not (null? #,y-binding)) . #,loop-preconditions))
   
   (set! loop-conditions #`((not (null? #,y-binding)) . #,loop-conditions))
   (parse-loop #`(loop-body (with #,y-binding = y and #,iter-binding = iter with x = #,y-binding . rest)))))
((for x on y . rest)
 (parse-loop #'(loop-body (for x on y by cdr . rest))))
]


@subsection{for x being the hash-keys in table: Hash iteration}


This binds @italic{var} to each of the keys in the @italic{hash-table}
in succession:

@racketblock[
  (loop for var being the hash-keys in hash-table ...)
]

You can bind the corresponding hash value to another variable like this:

@racketblock[
  (loop for var being the hash-keys in hash-table using (hash-value other-var) ...)
]

The reverse is also supported:

@racketblock[
  (loop for var being each hash-value in hash-table using (hash-key other-var) ...)
]

And the following extension is supported:

@racketblock[
  (loop for (key val) being the hash-pairs in hash-table ...)
]

@scheme[each] and @scheme[the] are interchangeable, as are the singular/plural forms of hash-keys, etc.

Iterating over hash tables is more difficult. Racket provides no way to get the "next" key and value pair from
a hash and remove it. Instead, it provides full-iteration functions such as @scheme[hash-map] and @scheme[hash-for-each].

A hash table can be rewritten as a list using @scheme[hash->list], but that would be a bad thing to do if the hash
was big.

The @scheme[hash-for-each] function can be used to create a generator, however, and the loop macro can iterate over generators. A generator using
@scheme[hash-for-each] will return @scheme[(void)] when iteration completes, but the loop macro requires @scheme[end-of-generator], because
@scheme[(void)] is ambiguous. So the clause is rewritten as an iteration over a generator.

Since Racket's hash iteration functions always provide both key and value, it makes sense to implement the
hash-pairs extension first. The singular @italic{hash-pair} can be used also, but it is simply rewritten
as @italic{hash-pairs}.

@CHUNK[<for-hash>
<for-hash-keys>
<for-hash-values>
((for (key value) being the hash-pairs in hash . rest)
 (parse-loop #`(loop-body (for (key value) over (make-hash-generator hash) . rest))))
((for (key value) being the hash-pair in hash . rest)
 (parse-loop #'(loop-body (for (key value) being the hash-pairs in hash . rest))))
((for something being each . rest)
 (parse-loop #'(loop-body (for something being the . rest))))
]

The generator is defined like this:

@CHUNK[<make-hash-generator>
(define (make-hash-generator hash)
  (generator ()
	     (begin 
	       (hash-for-each hash
			      (λ (k v)
				 (yield k v)))
	       (yield end-of-generator end-of-generator))))
]

@subsubsection{for x being the hash-keys in hash using...}

All of the standard Common Lisp variants for iterating over a hash table
are implemented in terms of the variant above.

@CHUNK[<for-hash-keys>
((for key being the hash-keys in hash using (hash-value value) . rest)
 (parse-loop #'(loop-body (for (key value) being the hash-pairs in hash . rest))))
((for key being the hash-keys in hash . rest)
 (parse-loop #'(loop-body (for (key value) being the hash-pairs in hash . rest))))
((for k being the hash-key in  hash . rest)
 (parse-loop #'(loop-body for k being the hash-keys in hash . rest)))
]

@CHUNK[<for-hash-values>
((for val being the hash-values in hash using (hash-key key) . rest)
 (parse-loop #'(loop-body (for (key value) being the hash-pairs in hash . rest))))
((for val being the hash-values in hash . rest)
 (parse-loop #'(loop-body (for (key value) being the hash-pairs in hash . rest))))
((for val being the hash-value . rest)
 (parse-loop #'(loop-body (for val being the hash-values . rest))))
]

@subsection{for x over y: Generator iteration}

For generator iteration, multiple values from @scheme[(yield)] are supported. The loop terminates when
the first of these values (or the only value) is @scheme[end-of-generator], whose value is defined
in this file.

Example:

@racketblock[
	     (loop for value over (generator ()
					   (for-each (λ (value)
							(yield value))
						     '(a b c d e f g))
					   end-of-generator))
	     ]

@CHUNK[<for-x-over-y>
((for (x . rest-vars) over y . rest)
 (let ((y-binding (datum->syntax stx (gensym))))
   (set! let-values-defs #`(((x . rest-vars) (#,y-binding)) . #,let-values-defs))
   (set! let-defs #`((#,y-binding y) . #,let-defs))
   (let set-precondition-loop ((variables #'(x . rest-vars)))
     (syntax-case variables ()
       (() #t)
       ((x . rest-vars) (begin (set! loop-preconditions
				#`((not (end-of-generator?  x)) . #,loop-preconditions))
			  (set-precondition-loop #'rest-vars)))))
   (parse-loop #'(loop-body rest))))
((for x over y . rest)
 (parse-loop #'(loop-body (for (x) over y . rest))))
]
   
@subsection{for x across y: Vector, string, and byte iteration}

@CHUNK[<for-x-across-y>
((for x across y . rest)
 (let* ((y-binding (datum->syntax stx (gensym)))
	(yix (datum->syntax stx (gensym)))
	(loop-condition #`(< #,yix (alen #,y-binding))))
   (set! let-defs #`((x #f) (#,yix 0) (#,y-binding y) . #,let-defs))
   (set! preiterations #`(#,@preiterations
			  (when #,loop-condition
				(set! x (aref #,y-binding #,yix)))))
   (set! loop-preconditions
	 #`(#,loop-condition . #,loop-preconditions))
   (set! iterations
	 #`((set! #,yix (add1 #,yix)) . #,iterations))
   (parse-loop #`(loop-body (with #,y-binding = y and #,yix = 0
			    with x = (if (>= #,yix (alen #,y-binding))
					 #f
					 (aref #,y-binding #,yix)) . rest)))))
]

@subsection{for x = y: Iterating over numbers}


@CHUNK[<for-x=y>
<for-x=y-then>
((for x = y . rest)
 (begin
   (set! let-defs #`((x #f) . #,let-defs))
   (set! loop-preconditions
	 #`((begin
	      (set! x y)
	      #t) . #,loop-preconditions))
   (parse-loop #'(loop-body rest))))
]

@CHUNK[<for-x=y-then>
((for x = y then step-form . rest)
 (begin
   (set! let-defs #`((x #f) . #,let-defs))
   (set! prologue #`(#,@prologue (set! x y)))
   (set! iterations #`((set! x step-form) . #,iterations))
   (parse-loop #'(loop-body rest))))
]

@CHUNK[<for-x-from-low>
<for-x-from-low-to-high>
((for x from low by step . rest)
 (let ((step-binding (datum->syntax stx (gensym))))
   (set! let-defs #`((#,step-binding step) . #,let-defs))
   (parse-loop #`(loop-body (for x = low then (+ x #,step-binding) . rest)))))
((for x from low . rest)
 (begin
   (parse-loop #'(loop-body (for x from low by 1 . rest)))))
((for x downfrom high . rest)
 (parse-loop #'(loop-body (for x from high by -1 . rest))))
]

@CHUNK[<for-x-from-low-to-high>
((for x from low to high by step . rest)
 (let ((high-binding (datum->syntax stx (gensym))))
   (set! let-defs #`((#,high-binding #f) . #,let-defs))
   (set! prologue #`(#,@prologue (set! #,high-binding high)))
   (set! loop-preconditions
	 #`((<= x #,high-binding) . #,loop-preconditions))
   (parse-loop #'(loop-body (for x from low by step . rest)))))
((for x from low to high . rest)
 (begin
   (parse-loop #'(loop-body (for x from low to high by 1 . rest)))))
((for x from low below high by step . rest)
 (let ((high-binding (datum->syntax stx (gensym))))
   (set! let-defs #`((#,high-binding #f) . #,let-defs))
   (set! prologue #`(#,@prologue (set! #,high-binding high)))
   (set! loop-preconditions
	 #`((< x #,high-binding) . #,loop-preconditions))
   (parse-loop #'(loop-body (for x from low by step . rest)))))
((for x from low below high . rest)
 (begin
   (parse-loop #'(loop-body (for x from low below high by 1 . rest)))))
((for x from low upto high . rest)
 (begin
   (parse-loop #'(loop-body (for x from low to high . rest)))))
((for x from high downto low by step . rest)
 (let ((low-binding (datum->syntax stx (gensym))))
   (set! let-defs #`((#,low-binding #f) . #,let-defs))
   (set! prologue #`(#,@prologue (set! #,low-binding low)))
   (set! loop-preconditions
	 #`((>= x #,low-binding) . #,loop-preconditions))
   (parse-loop #`(loop-body (for x = high then (- x step) . rest)))))
((for x from high downto low . rest)
 (begin
   (parse-loop #'(loop-body (for x from high downto low by 1 . rest)))))
((for x downfrom high to low . rest)
 (parse-loop #'(loop-body (for x from high downto low . rest))))
((for x from high above low by step)
 (let ((low-binding (datum->syntax stx (gensym))))
   (set! let-defs #`((#,low-binding #f) . #,let-defs))
   (set! prologue #`(#,@prologue (set! #,low-binding low)))
   (set! loop-preconditions
	 #`((> x #,low-binding) . #,loop-preconditions))
   (parse-loop #`(loop-body (for x = high then (- x step) . rest)))))
((for x from  high above low . rest)
 (begin
   (parse-loop #'(loop-body (for x from high above low by 1)))))
]
 

@CHUNK[<individual-for-clauses>
<for-hash>
<for-x-in-y>
<for-x-on-y>
<for-x-over-y>
<for-x-across-y>
<for-x=y>
<for-x-from-low>
]


@section{WITH: Binding variables}

@italic{With} is used like this:

@racketblock[ (loop with x = value ...) ]

It binds @italic{x} to the given @italic{value} by wrapping everything in a @scheme[let*] form. There is a variant:

@racketblock[(loop with x = value and y = other-value)]

This variant wraps using a @scheme[let] form instead of @scheme[let*]. Of course the two variants can be mixed,
producing a gnarled nest of @scheme[let] and @scheme[let*] forms over the body of the loop.

@CHUNK[<with>
((_ (with x = value and y = other-value . rest))
 (begin
   (set! current-gnarled-let-def
	 #`(#,@current-gnarled-let-def (y other-value)))
   (parse-loop #'(loop-body (with* x = value . rest)))))
((_ (with* x = value and y = other-value . rest))
 (parse-loop #'(loop-body (with x = value and y = other-value . rest))))
((_ (with* x = value . rest))
 (begin
   (set! gnarled-let-defs
	 #`(#,@gnarled-let-defs (#,@current-gnarled-let-def (x value))))
   (set! current-gnarled-let-def #'())
   (parse-loop #'(loop-body rest))))
((_ (with x = value . rest))
 (begin
   (set! gnarled-let-defs #`(#,@gnarled-let-defs * ((x value))))
   (parse-loop #'(loop-body rest))))
]

@section{FINALLY}

The @italic{finally} clause executes at the end of iteration. 

@CHUNK[<finally>
((_ (finally form . rest))
 (begin
   (set! epilogue #`(#,@epilogue form))
   (parse-loop #'(loop-body rest))))
]

@section{INITIALLY}

The @italic{initially} clauses execute at the beginning of iteration,
just after all variables have been initialized.

@CHUNK[<initially-clause>
((_ (initially form . rest))
 (begin
   (set! initially-prologue #`(#,@initially-prologue form))
   (parse-loop #'(loop-body rest))))
]
    

@section{@scheme[always], @scheme[never], and @scheme[thereis]}

@CHUNK[<always/never/thereis>
((_ (thereis form . rest))
 (let ((success? (datum->syntax stx (gensym))))
   (set! let-defs #`((#,success? #f) . #,let-defs))
   (set! body #`((when form
		       (set! #,success? #t)
		       (return #t)) . #,body))
   (parse-loop #`(loop-body (finally (return #,success?) . rest)))))
((_ (always form . rest))
 (begin
   (let ((success? (datum->syntax stx (gensym))))
     (set! let-defs #`((#,success? #t) . #,let-defs))
     (set! body #`((when (not form)
			 (set! #,success? #f)
			 (return #f)) . #,body))
     (parse-loop #`(loop-body (finally (return #,success?) . rest))))))
((_ (never form . rest))
 (parse-loop #'(loop-body (always (not form) . rest))))
]

@CHUNK[<loop-literals>
(for by as being by the each hash-key hash-keys hash-value hash-values hash-pair hash-pairs from while do do-internal collect collecting repeat repeating with with* sum summing append then
     appending matching nconc nconcing cons consing count _count counting string-append
     minimize minimizing maximize maximizing below above to downto downfrom upto in into on across over = until always never thereis and
     end else named initially finally if when unless return with-collection-type)
]

@CHUNK[<all-the-rest>
(define-syntax loop-body
  (λ (stx)
     (define call-with-cc #'call/ec)
     (define return-continuation #'loop-return)
     (define collection #'collection)
     (define initial-collection #'#f)
     (define count* #'count)
     (define initial-count #'#f)
     (define sum* #'sum)
     (define min #'min)
     (define max  #'max)
     (define reverse? #'reverse?)
     (define reverse-value #'#t)
     (define string-accumulator #'string-accumulator)
     (define initial-string #'#f)
     (define initial-sum #'#f)
     (define and? #f)

     (define collection-type #''list)
     

     ;; Syntax accumulators

     (define prologue #'())
     (define initially-prologue #'())
     (define epilogue #'())
     (define iterations #'())
     (define let-values-defs #'())
     (define current-condition #'())
     (define loop-conditions #'())
     (define preiterations #'())
     (define loop-preconditions #'())
     (define action-clauses #'())
     (define current-cond-body #'())
     (define body #'())
     (define list-defs #'())
     (define let-defs #'())
     (define gnarled-let-defs #'())
     (define current-gnarled-let-def #'())
     <define-add-action-clause>
     
     (let parse-loop ((stx stx))
       (define first-word (syntax-case stx ()
			    ((_ ()) #f)
			    ((_ (first . rest))
			       (syntax->datum #'first))))
       ;; Stupid bug:  The word "count" cannot be passed to this macro from
       ;;              outside the module. Syntax-case won't be able to match
       ;;              it. So we work around it by stripping outside-module
       ;;              scope information from the word. But then we also have
       ;;              to rename it to avoid an infinite loop.
       (cond ((eq? first-word 'count)
	      (syntax-case stx ()
		  ((_ (first . rest))
		   (parse-loop #'(loop-body (_count . rest))))))
	     (else
	      (syntax-case stx <loop-literals>
		((_ ())
		 (cond (<action-boilerplate-guard>
			(let ((let-vars (get-let-vars let-defs)))
			  <loop-body>))
		       (else
			(parse-loop #'(loop-body (end))))))
		<with>
		<initially-clause>
		<finally>
		<always/never/thereis>
		<rewrite-if-clauses>
		<collect-if-clauses>
		<collect-else-if>
		<while/until>
		<repeat>
		<and>
		<end>
		<do-clause>
		<do-internal>
		<do-internal/2>
		<collect-clause>
		<min/max>
		<cons-into>
		<with-collection-type>
		<append-clause>
		<sum-clause>
		<count-clause>
		<universal-for-clause>))))))
(provide loop-body)

(define-syntax loop
  (syntax-rules (named)
    ((_ named block-name . body)
     (call/ec
      (λ (block-name)
	 (loop . body))))
    ((_ . body)
     (loop-body body))))
(provide loop)

]

@CHUNK[<local-macros>
(define-syntax unwind-protect
  (syntax-rules ()
    ((_ value-form cleanup-form)
     (dynamic-wind (let ((ok? #t))
		     (lambda ()
		       (if ok?
			   (set! ok? #f)
			   (error "Re-entering UNWIND-PROTECT is prohibited."))))
	 (lambda () value-form)
	 (lambda () cleanup-form)))))

(define-syntax gnarled-let-nest
  (syntax-rules (*)
    ((_ () . body)
     (begin . body))
    ((_ (* (bindings ...) . more-bindings) . body)
     (let* (bindings ...)
       (gnarled-let-nest more-bindings . body)))
    ((_ ((bindings ...) . more-bindings) . body)
     (let (bindings ...)
       (gnarled-let-nest more-bindings . body)))
    ((_ (* (bindings ...)) . body)
     (let* (bindings ...) . body))
    ((_ ((bindings ...)) . body)
     (let (bindings ...) . body))))
]

@CHUNK[<supporting-functions>
(define-for-syntax (syntax-null? stx)
  (syntax-case stx ()
    (() #t)
    (_ #f)))

(define-for-syntax (syntax-reverse stx)
  (let loop ((rest stx)
	     (result #'()))
    (syntax-case rest ()
      (() result)
      ((hd . tl) (loop #'tl #`(hd . #,result))))))

(define-for-syntax (get-let-vars stx)
  (let loop ((rest stx)
	     (result #'()))
    (syntax-case rest ()
      (() (syntax-reverse result))
      (((var . value) . rest)
       (loop #'rest
	     #`(var . #,result))))))

(define-for-syntax (syntax-find pred? syntax-list)
  (let loop ((rest syntax-list))
    (syntax-case rest ()
      (() #f)
      ((hd . tl)
       (if (pred? #'hd)
	   #'hd
	   (loop #'tl))))))

(define-for-syntax (add-iterations let-vars iterations)
  (let loop ((let-vars let-vars)
	     (iterations iterations)
	     (result #'()))
    (syntax-case let-vars ()
      (() (syntax-reverse result))
      ((var . rest)
       (let ((iter (syntax-find (λ (stx)
				   (syntax-case stx ()
				       ((var2 . fuckit)
					(eq? (syntax->datum #'var2)
					     (syntax->datum #'var)))))
				iterations)))
	 (loop #'rest iterations (if iter (syntax-case iter ()
					    ((var body) #`(body . #,result)))
				     #`(var . #,result))))))))
			       

(define (aref arr n)
  ((cond ((vector? arr) vector-ref)
	 ((string? arr) string-ref)
	 ((bytes? arr) bytes-ref)) arr n))

(define (alen arr)
  ((cond ((vector? arr) vector-length)
	 ((string? arr) string-length)
	 ((bytes? arr) bytes-length)) arr))

(define-for-syntax (print-syntax stx)
  (displayln (syntax->datum stx)))
<list->hash>

]