GeneralDefining a new command which expands into several lines

LaTeX specific issues not fitting into one of the other forums of this category.
Post Reply
curiouslearn
Posts: 105
Joined: Fri Nov 30, 2007 11:32 pm

Defining a new command which expands into several lines

Post by curiouslearn »

I am trying to write a small exam package of my own. As of now it is only a set of some commands. To generate a list of multiple choice answers at the end of the document, I am embedding the following Python code in the latex file (I am using the python.sty package)

Code: Select all

\begin{python}
	print r"\begin{tabular}{r@{) }l}"
	Qlist=range(11)
	for i in Qlist:
	    print r"%i & \ref{%i} \\" % (i+1,i+1)
	print r"\end{tabular}" 	
\end{python}


The code works fine on its own and there is no problem. My objective is to wrap this code in a latex command. I tried the following:

Code: Select all

\def\PrintAnswers{
\begin{python}
	print r"\begin{tabular}{r@{) }l}"
	Qlist=range(11)
	for i in Qlist:
	    print r"%i & \ref{%i} \\" % (i+1,i+1)
	print r"\end{tabular}" 	
\end{python}}
This does not, however, work. I get errors like
! Use of \@python doesn't match its definition.
<argument> \def \reserved@a {
\def \@currenvir {tabular}\edef \@currenvline {...
l.212 %\end{python}
I am not sure why. In python the spacing matters. Is it possible that this could be because the command \PrintAnswers does not expand exactly to the desired code? Is there a way I can define a command \PrintAnswers such that when the latex encounters it, it expands it to

Code: Select all

\begin{python}
	print r"\begin{tabular}{r@{) }l}"
	Qlist=range(11)
	for i in Qlist:
	    print r"%i & \ref{%i} \\" % (i+1,i+1)
	print r"\end{tabular}" 	
\end{python}
as if I had typed it in the latex file by hand (i.e., keep the indentation and carriage returns as entered). Any help would be greatly appreciated.

Recommended reading 2024:

LaTeXguide.org • LaTeX-Cookbook.net • TikZ.org

NEW: TikZ book now 40% off at Amazon.com for a short time.

phi
Posts: 577
Joined: Tue Oct 21, 2008 8:10 pm

Defining a new command which expands into several lines

Post by phi »

Hello,
the problem with packages like this is that they have to change some TeX internals which makes it impossible to use them inside a command. Is it necessary to use Python code for your list generation command? TeX is a complicated, but complete programming language that can be used for things like that. For example, the following prints a table with eleven rows:

Code: Select all

\documentclass{article}

\newcommand*\PrintAnswers{%
  \begin{tabular}{r@{) }l}%
  \PrintAnswersRec{1}{11}%
  \end{tabular}%
}

\newcommand*\PrintAnswersRec[2]{%
  \number#1 & \ref{\number#1} \\%
  \ifnum#1<#2 %
    \expandafter\PrintAnswersRec
      \expandafter{\number\numexpr#1+1\expandafter}%
      \expandafter{\number#2\expandafter}%
  \fi
}

\begin{document}
\PrintAnswers
\end{document}
curiouslearn
Posts: 105
Joined: Fri Nov 30, 2007 11:32 pm

Re: Defining a new command which expands into several lines

Post by curiouslearn »

Thanks very much phi. Your solution works great. I do not understand it but will try to figure it out. Thanks again.

Do I have to learn Tex programming or Latex programming to be able to do this kind of stuff? If so, can someone please suggest a good book to learn it from?
User avatar
Stefan Kottwitz
Site Admin
Posts: 10348
Joined: Mon Mar 10, 2008 9:44 pm

Defining a new command which expands into several lines

Post by Stefan Kottwitz »

Hi,

here are some links to good TeX books: plain TeX ressources. I recommend the TeXbook, though I often prefer to look into "TeX by topic" because I would find some things more quickly.

Stefan
LaTeX.org admin
phi
Posts: 577
Joined: Tue Oct 21, 2008 8:10 pm

Defining a new command which expands into several lines

Post by phi »

curiouslearn wrote:If so, can someone please suggest a good book to learn it from?
TeX by Topic should suffice (at least, it was sufficient for me), but read it very carefully, since TeX is totally different from most other programming languages. You'll also need to read the eTeX manual to write a purely expandable tail-recursive loop like the one posted. It is possible to use high-level commands to do things like this, but these can have unexpected side effects because they are not intended for recursive macros. For example, the following works:

Code: Select all

\newcounter{AnswerIndex}
\newcounter{AnswerCount}

\newcommand*\PrintAnswersLaTeX{%
  \begin{tabular}{r@{) }l}%
  \setcounter{AnswerIndex}{1}%
  \setcounter{AnswerCount}{11}%
  \PrintAnswersLaTeXRec
  \end{tabular}%
}

\newcommand*\PrintAnswersLaTeXRec{%
  \arabic{AnswerIndex} & \ref{\arabic{AnswerIndex}}%
  \ifthenelse{\value{AnswerIndex}<\value{AnswerCount}}{%
    \\%
    \addtocounter{AnswerIndex}{1}%
    \PrintAnswersLaTeXRec
  }{}%
}
But it has several drawbacks: It needs two integer registers, is not tail-recursive (which is not harmful in this case, since the recursive macro takes no parameters), is not expandable, and even exposes errors in certain circumstances (e.g. empty rows).
curiouslearn
Posts: 105
Joined: Fri Nov 30, 2007 11:32 pm

Re: Defining a new command which expands into several lines

Post by curiouslearn »

Phi and Stefan, thanks very much for the references. I will look into those.
Post Reply