Open main menu

Difference between revisions of "System Macros/Loops and Recursion"

(Added section Recursion and expansion)
m
 
(8 intermediate revisions by 6 users not shown)
Line 7: Line 7:
 
number.
 
number.
  
=== <cmd>dorecurse</cmd> ===
+
=== {{cmd|dorecurse}} ===
 
<texcode>
 
<texcode>
 
\dorecurse {n} {whatever we want}
 
\dorecurse {n} {whatever we want}
Line 15: Line 15:
 
used in situations where Plain TeX's <code>\loop</code> macro
 
used in situations where Plain TeX's <code>\loop</code> macro
 
ungracefully fails. The current value of the counter is
 
ungracefully fails. The current value of the counter is
available in <code>\recurselevel</code>, before as well as after
+
stored in <code>\recurselevel</code>, and is available
the <code>whatever we want</code> stuff.
+
for use anywhere within the second parenthesis
 +
where <code>whatever we want</code> text is found.
  
 
<context source="yes">
 
<context source="yes">
Line 37: Line 38:
  
 
Both <code>\recurselevel</code> and <code>\recursedepth</code> are
 
Both <code>\recurselevel</code> and <code>\recursedepth</code> are
macros. The real conters are hidden from the user because
+
macros. The real counters are hidden from the user because
 
we don't want any interference.
 
we don't want any interference.
  
 +
=== {{cmd|doloopoverlist}} ===
 +
<texcode>
 +
\doloopoverlist {a, b, c} {current letter is: “\recursestring”\par}
 +
</texcode>
 +
 +
As the command name reads, it loops over the list values.
 +
 +
<context source="yes">
 +
\doloopoverlist
 +
  {a, b, c}
 +
  {current letter is: “\recursestring”\par}
 +
</context>
 +
 +
{{cmd|recursestring}} is used instead of {{cmd|recurselevel}}.
 +
 +
<context source="yes">
 +
\doloopoverlist{\tf,\ss,\tt}
 +
  {\bgroup\recursestring\doloopoverlist{\rm,\it,\bf,\bi,\sc}
 +
    {\bgroup\recursestring a̱ḇc̱  a̲b̲c̲\quad\egroup}\egroup\par}
 +
</context>
 +
 +
It also allows commands, as contained in the previous code snippet.
  
=== <cmd>dostepwiserecurse</cmd> ===
+
=== {{cmd|dostepwiserecurse}} ===
 
The simple command <code>\dorecurse</code> is
 
The simple command <code>\dorecurse</code> is
 
a special case of the more general:
 
a special case of the more general:
Line 58: Line 81:
 
</texcode>
 
</texcode>
  
=== <cmd>doloop</cmd> <cmd>exitloop</cmd> ===
+
=== {{cmd|doloop}} {{cmd|exitloop}} ===
 
Sometimes loops are not determined by counters, but by
 
Sometimes loops are not determined by counters, but by
 
(a combinations of) conditions. We therefore implement a
 
(a combinations of) conditions. We therefore implement a
Line 71: Line 94:
 
</texcode>
 
</texcode>
  
When needed, one can call for <code>\looplevel</code> and
+
When needed, one can call for <code>\recurselevel</code> and
<code>\loopdepth</code>.
+
<code>\recursedepth</code>.
  
 
The loop is executed at least once, so beware of situations
 
The loop is executed at least once, so beware of situations
Line 126: Line 149:
 
</context>
 
</context>
  
For further discussion on loops and expansion, see [[System_Macros/Expansion_Control]] as well as this [http://randomdeterminism.wordpress.com/2009/03/05/tex-programming-the-past-the-present-and-the-future/ blog post].
+
For further discussion on loops and expansion, see [[System_Macros/Expansion_Control|Expansion control]] as well as this [http://randomdeterminism.wordpress.com/2009/03/05/tex-programming-the-past-the-present-and-the-future/ blog post].
  
< '''Prev:''' [[System Macros/Branches and Decisions|Brancjes & Decisions]] | '''Top:''' [[System Macros]] | '''Next:''' [[System Macros/Action Processing|Action Processing]] >
+
< '''Prev:''' [[System Macros/Branches and Decisions|Branches & Decisions]] | '''Top:''' [[System Macros]] | '''Next:''' [[System Macros/Action Processing|Action Processing]] >
  
[[Category:ConTeXt programming]]
+
[[Category:Programming and Databases]]
[[Category:Inside ConTeXt]]
+
[[Category:Tools]]

Latest revision as of 15:51, 12 September 2023

< Prev: Branches & Decisions | Top: System Macros | Next: Action Processing >

TeX does not offer us powerful for-loop mechanisms. On the other hand its recursion engine is quite unique. We therefore identify the for-looping macros by this method. The most simple alternative is the one that only needs a number.

\dorecurse

\dorecurse {n} {whatever we want}

This macro can be nested without problems and therefore be used in situations where Plain TeX's \loop macro ungracefully fails. The current value of the counter is stored in \recurselevel, and is available for use anywhere within the second parenthesis where whatever we want text is found.

\dorecurse               % inner loop
  {10}
  {\recurselevel:          % outer value
     \dorecurse          % inner loop
       {\recurselevel}     % outer value
       {\recurselevel}     % inner value
     \dorecurse          % inner loop
       {\recurselevel}     % outer value
       {\recurselevel}     % inner value
   \endgraf}

 

In this example the first, second and fourth \recurselevel concern the outer loop, while the third and fifth one concern the inner loop. The depth of the nesting is available for inspection in \recursedepth.

Both \recurselevel and \recursedepth are macros. The real counters are hidden from the user because we don't want any interference.

\doloopoverlist

\doloopoverlist {a, b, c} {current letter is: “\recursestring\par}

As the command name reads, it loops over the list values.

\doloopoverlist
  {a, b, c}
  {current letter is: “\recursestring\par}

 

\recursestring is used instead of \recurselevel.

\doloopoverlist{\tf,\ss,\tt}
  {\bgroup\recursestring\doloopoverlist{\rm,\it,\bf,\bi,\sc}
    {\bgroup\recursestring a̱ḇc̱  a̲b̲c̲\quad\egroup}\egroup\par}

 

It also allows commands, as contained in the previous code snippet.

\dostepwiserecurse

The simple command \dorecurse is a special case of the more general:

\dostepwiserecurse {from} {to} {step} {action}

This commands accepts positive and negative steps. Illegal values are handled as good as possible and the macro accepts numbers and counters.

\dostepwiserecurse  {1} {10}  {2} {...}
\dostepwiserecurse {10}  {1} {-2} {...}

\doloop \exitloop

Sometimes loops are not determined by counters, but by (a combinations of) conditions. We therefore implement a straightforward loop, which can only be left when we explicitly exit it. Nesting is supported. First we present a more extensive alternative.

\doloop
  {Some kind of typesetting punishment \par
   \ifnum\pageno>100 \exitloop \fi}

When needed, one can call for \recurselevel and \recursedepth.

The loop is executed at least once, so beware of situations like:

\doloop {\exitloop some commands}

It's just a matter of putting the text into the \if statement that should be there anyway, like in:

\doloop {\ifwhatever \exitloop \else some commands\fi}

You can also quit a loop immediately, by using \exitloopnow instead. Beware, this is more sensitive for conditional errors.

Recursion and expansion

Using recursion to build tables requires some particular attention:

\bTABLE
\bTR
\dorecurse{8}{\expanded{\bTD\recurselevel\eTD}}
\eTR
\eTABLE

 

Multi-dimensional tables offer another illustration:

\bTABLE
\dorecurse{8}{
	\bTR
	\dorecurse{5}{\bTD #1,##1 \eTD}
	\eTR
}
\eTABLE

 

Alternatively, (mkiv only?)

\bTABLE
    \dorecurse{8}{\bTR
        \dorecurse{5}{\bTD \currentTABLErow,\currentTABLEcolumn \eTD}
    \eTR}
\eTABLE

 

For further discussion on loops and expansion, see Expansion control as well as this blog post.

< Prev: Branches & Decisions | Top: System Macros | Next: Action Processing >