Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

At a basic level TeX does not provide a for-loop construct, but allows tail-end recursion, however Knuth defined \loop in the plain macros. Coders have been coming with variations of their own ever since.

The ifthen package provides the whiledo loop and there is a forloop macro. TikZ provides similarly a foreach macro.

Is there a canonical way to write a forloop in LaTeX, TeX and friends. How would you write the following?

\def\triangle#1{{\def\bull{}%
\count1=0
\loop
   \edef\bull{$\bullet$\bull}
   \ifnum\count1<#1
      \advance\count1 by 1
      \centerline{\bull}
      \vskip-7.7pt
      \repeat
      \vskip 7.7pt\relax}}

which will produce a triangle made of dots

        *
     *    *
  *     *    *

As typically found in programming texts, can you re-write it in a better way?

share|improve this question
    
Should this be community wiki? There is no definite answer. And there are already three different “right” answers. –  Caramdir Sep 30 '10 at 19:37
    
@caramdir I agree it should be a community wiki, I will change after 24 hours. –  Yiannis Lazarides Sep 30 '10 at 19:48
    
Changed to community wiki. –  Yiannis Lazarides Sep 30 '10 at 20:46
    
I'll CW the answers, then –  Joseph Wright Oct 1 '10 at 15:45

7 Answers 7

Here is how I will do it in ConTeXt:

\def\TRIANGLE#1%
  {\dorecurse{#1}
     {\centerline{$\dorecurse{\recurselevel}{{\bullet}}$}}}

\starttext \TRIANGLE{4} \stoptext

The extra braces around \bullet is so that is has math class ord rather than bin.

share|improve this answer
    
what does \recurselevel do? –  Yiannis Lazarides Sep 30 '10 at 16:59
    
\recurselevel is the value of the current "level". So, in the first iteration it is 1, in the second iteration it is 2, and so on. Similar to the value of \count1 in your example. –  Aditya Sep 30 '10 at 17:01

Here's a Plain TeX macro that's similar to the one in the question except it handles things like being used from horizontal mode or a change to \mathsurround.

\def\triangle#1{%
        \par
        \vbox{%
                \baselineskip4.3pt
                \m@th
                \toks@{}%
                \count@#1
                \loop\ifnum\count@>\z@
                        \advance\count@\m@ne
                        \toks@\expandafter{\the\toks@{\bullet}}%
                        \centerline{$\the\toks@$}%
                \repeat
        }%
}

It should be pretty fast too. \setbox0\vbox{\triangle{500}} takes about .2 seconds on my laptop (an average over 1000 trials). Using 100 (about the largest that fits on a page) instead of 500 takes .007 seconds.

I also find the loop pretty readable, modulo the @ in the names which just takes getting used to and isn't part of the loop really.

share|improve this answer

A couple of LaTeX3 solutions. You could do this as a replication

\documentclass{article}
\usepackage{expl3,fixltx2e}
\begin{document}
\ExplSyntaxOn
\int_new:N \l_my_int
\prg_replicate:nn { 3 } {
  \int_incr:N \l_my_int
  \centerline { \prg_replicate:nn { \l_my_int } { \( \bullet \) } } 
}
\ExplSyntaxOff
\end{document}

Alternatively, the while-do approach:

\documentclass{article}
\usepackage{expl3,fixltx2e}
\begin{document}
\ExplSyntaxOn
\int_new:N \l_my_int
\intexpr_while_do:nn { \l_my_int < 4 } {
  \int_incr:N \l_my_int
  \centerline { \prg_replicate:nn { \l_my_int } { \( \bullet \) } } 
}
\ExplSyntaxOff
\end{document}

I should add that there are limitations on the replication system in expl3 (usually at the tens of thousands of replications!). So for a really big loop while-do might be safer.

share|improve this answer

A LuaTeX solution could look like this:

\def\luatriangle#1{%
\directlua{

  for i = 1,#1 do
    tex.sprint(string.format("\\centerline{\%s}\\vskip-7.7pt", string.rep("$\\bullet$",i) ))
  end

}}

There is only one little problem here, because the macro contains \\ and TeX complains about it. So the solution (and the advice) is to put all Lua code into a separate file and do something like:

\def\luatriangle#1{%
\directlua{
  dofile("loop.lua")
  loop(#1)
}}

and the Lua file (loop.lua):

function loop( count )
  for i = 1,count do
      tex.sprint(string.format("\\centerline{%s}\\vskip-7.7pt", string.rep("$\\bullet$",i) ))
  end
end

Not the best LuaTeX example. The ugly part is the string.format(...) line, but I think the loop part is very readable.

share|improve this answer

Kees van der Laan wrote an article titled "Paradigms: Loops" which discusses several different TeX-based approaches for writing loops. See MAPS 17.

share|improve this answer

Another solution, this time using Metapost. Again, this is tuned for ConTeXt, but should be easy to modify for LaTeX.

\startMPinclusions[+]
  vardef TRIANGLE(expr n) = 
    bullet_sep  := 5bp ;
    bullet_size := 3bp ;

    path bullet ;
    bullet := fullcircle scaled bullet_size ;

    for i := 1 upto n:
      y := -i * bullet_sep ;
      x := - (i-1)/2 * bullet_sep ;
      for j := 1 upto i :
        fill bullet shifted ( x + j*bullet_sep, y) ;
      endfor ;
    endfor ;
  enddef ;
\stopMPinclusions

\def\TRIANGLE#1{\startMPcode TRIANGLE(#1); \stopMPcode}
share|improve this answer
    
Hmm, not entirely inappropriate for the task given, but I got the impression it was just an example task and he really wanted to know about TeX-level looping... –  SamB Dec 1 '10 at 5:16
    
... of course, for all I know, that is TeX level :-) –  SamB Dec 1 '10 at 5:17

This is essentially same as Partick's solution, but adapted to ConTeXt, and much more readable, IMO

\def\TRIANGLE#1{\ctxlua{third.triangle(#1)}}

\startluacode
  third = third or {}
  function third.triangle(n)
    for i=1,n do
      context.centerline(string.rep("$\\bullet$", i))
      context.blank{ "-7.7pt" }
    end
  end
\stopluacode

See Context lua documents manual for details of how context function works.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.