11

I am trying to write a simple nested loop in LaTex, without using any special packages, using only the \loop...\if... \repeat syntax. I think I may be lacking a basic understanding of the rules for this construct, namely, are nested loops allowed?

My application is a simple diary generator, below is a simplified version of the code which does not work. Instead of printing out 12 months worth of 30 days, it gives the output at the bottom of the page.

\newcounter{currentday}
\newcounter{currentmonth}
\newcommand{thecurrentmonth}{\arabic{currentmonth}}
\newcommand{thecurrentday}{\arabic{currentday}}

\newcommand{\makewholediaryflat}{%

   \setcounter{currentday}{1}
   \setcounter{currentmonth}{1}


   \loop % MONTH
     Including a month: \thecurrentmonth

     \setcounter{currentday}{1}%

     \loop% DAY
       Inputting Day \thecurrentday of month \thecurrentmonth

       \addtocounter{currentday}{1}

       Deciding whether to input day \thecurrentday...

       \ifnum\value{currentday}< 30
      \repeat% DAY

      \addtocounter{currentmonth}{1}

      Deciding whether to input month \thecurrentmonth...

      \ifnum\value{currentmonth}<13
    \repeat% MONTH

  }

\begin{document}
  \makewholediaryflat
\end{document}

Any simple thing that I am missing here as to why this would not work? The output from the program is:

Including a month: 1
Inputting Day 1of month 1
Deciding whether to input day 2...
Inputting Day 2of month 1
Deciding whether to input day 3...
Inputting Day 3of month 1
Deciding whether to input day 4...
Inputting Day 4of month 1
Deciding whether to input day 5...
Inputting Day 5of month 1
Deciding whether to input day 6...
Inputting Day 6of month 1
Deciding whether to input day 7...
Inputting Day 7of month 1
Deciding whether to input day 8...
Inputting Day 8of month 1
Deciding whether to input day 9...
Inputting Day 9of month 1
Deciding whether to input day 10...
Inputting Day 10of month 1
Deciding whether to input day 11...
Inputting Day 11of month 1
Deciding whether to input day 12...
Inputting Day 12of month 1
Deciding whether to input day 13...
Inputting Day 13of month 1
Deciding whether to input day 14...
Inputting Day 14of month 1
Deciding whether to input day 15...
Inputting Day 15of month 1
Deciding whether to input day 16...
Inputting Day 16of month 1
Deciding whether to input day 17...
Inputting Day 17of month 1
Deciding whether to input day 18...
Inputting Day 18of month 1
Deciding whether to input day 19...
Inputting Day 19of month 1
Deciding whether to input day 20...
Inputting Day 20of month 1
Deciding whether to input day 21...
Inputting Day 21of month 1
Deciding whether to input day 22...
Inputting Day 22of month 1
Deciding whether to input day 23...
Inputting Day 23of month 1
Deciding whether to input day 24...
Inputting Day 24of month 1
Deciding whether to input day 25...
Inputting Day 25of month 1
Deciding whether to input day 26...
Inputting Day 26of month 1
Deciding whether to input day 27...
Inputting Day 27of month 1
Deciding whether to input day 28...
Inputting Day 28of month 1
Deciding whether to input day 29...
Inputting Day 29of month 1
Deciding whether to input day 30...
Inputting Day 30of month 1
Deciding whether to input day 31...
Deciding whether to input month 2...
Deciding whether to input month 3...
Deciding whether to input month 4...
Deciding whether to input month 5...
Deciding whether to input month 6...
Deciding whether to input month 7...
Deciding whether to input month 8...
Deciding whether to input month 9...
Deciding whether to input month 10...
Deciding whether to input month 11...
Deciding whether to input month 12...
Deciding whether to input month 13...
Deciding whether to input month 14...
Deciding whether to input month 15...
Deciding whether to input month 16...
Deciding whether to input month 17...
Deciding whether to input month 18...
Deciding whether to input month 19...
Deciding whether to input month 20...
Deciding whether to input month 21...
Deciding whether to input month 22...
Deciding whether to input month 23...
Deciding whether to input month 24...
Deciding whether to input month 25...
Deciding whether to input month 26...
Deciding whether to input month 27...
Deciding whether to input month 28...
Deciding whether to input month 29...
Deciding whether to input month 30...
Deciding whether to input month 31...

3 Answers 3

17

The inner \loop must be enclosed in braces

\newcommand{\makewholediaryflat}{%
  \setcounter{currentday}{1}%
  \setcounter{currentmonth}{1}%
  \loop % MONTH
    Including a month: \thecurrentmonth

    {\loop % DAY
      Inputting Day \thecurrentday of month \thecurrentmonth

      \addtocounter{currentday}{1}

      Deciding whether to input day \thecurrentday...

    \ifnum\value{currentday} < 5
    \repeat % DAY
    }

    \setcounter{currentday}{1}%
    \addtocounter{currentmonth}{1}

    Deciding whether to input month \thecurrentmonth...
  }
  \ifnum\value{currentmonth} < 13%
  \repeat % MONTH
}

You should however be careful with empty lines in the definition. TeX is not "free form" and an empty line starts a new paragraph.

11

\loop works by defining a macro, \iterate, which holds the body of the loop (until \repeat). When you try to nest \loops, there are two problems:

  • The first \loop thinks that its body is delimited by te first \repeat rather than the second. This is solved by hiding that first \repeat within braces.

  • The inner \loop redefines \iterate to be equal to its own body. This is solved by putting that inner \loop...\repeat construct in a group.

Both can be done at the same time, by enclosing the inner \loop...\repeat within braces. It has nothing to do with "putting the body of the loop in braces". For your particular application, see egreg's answer.

\newcount\X
\newcount\Y
\loop
\Y = 0
\advance \X by 1
{%
  \loop
  \advance \Y by 1
  \message{\the\X,\the\Y}
  \ifnum \Y < 10
  \repeat
}%
\ifnum \X < 10
\repeat
0
4

The \loop body needs to be a block:

\newcommand{\makewholediaryflat}{%
  \setcounter{currentday}{1}%
  \setcounter{currentmonth}{1}%
  \loop{ % MONTH
    Including a month: \thecurrentmonth

    \loop{ % DAY
      Inputting Day \thecurrentday of month \thecurrentmonth

      \addtocounter{currentday}{1}

      Deciding whether to input day \thecurrentday...
    }
    \ifnum\value{currentday} < 5
    \repeat % DAY

    \setcounter{currentday}{1}%
    \addtocounter{currentmonth}{1}

    Deciding whether to input month \thecurrentmonth...
  }
  \ifnum\value{currentmonth} < 13%
  \repeat % MONTH
}
2
  • Shouldn't it be reset by the line \setcounter{currentday}{1}, on the next iteration of the month loop?
    – user839768
    Commented Jul 11, 2011 at 22:59
  • Sorry, that was bull. What you really need to do is enclose the loop body in braces. I'll edit.
    – Kerrek SB
    Commented Jul 11, 2011 at 23:27

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .