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.

Original question

I would like to create a metacommand for creating new projection commands. Specifically, \newproj{\cmd}{<n>}{<m>} should create \cmd as a new command of <n> (mandatory) arguments that always expands to the <m>th argument.

For example, if we have \newproj{\fst}{2}{1} and \newproj{\snd}{2}{2}, then \fst{x}{y} should expand to x whereas \snd{x}{y} should expand to y.

Here is my attempt at this:

\documentclass{article}

\newcommand*{\newproj}[3]{%
  \newcommand*#1[#2]{%
    \expandafter#\expandafter##3%
  }%
}

\newproj{\fst}{2}{1}
\newproj{\snd}{2}{2}

\begin{document}
\begin{tabular}{ll}
\verb^\fst{x}{y}^:& \fst{x}{y} \\
\verb^\snd{x}{y}^:& \snd{x}{y}
\end{tabular}
\end{document}

Unfortunately, this gives the error "Illegal parameter number in definition of \newproj. <to be read again> \expandafter" How can I use a parameter as a function of some integer or metaparameter?

Extended question: indirection via a macro

A.Ellett and Hendrik Vogt suggest using \newcommand*#1[#2]{###3} because ## expands to #. This works perfectly if a positive integer is passed as #3 to \newproj! However, suppose that I pass a macro to \newproj as #3. How can I use expansion of a macro to dynamically select a parameter?

For example, the following should produce the correct results. However, it gives the error "Illegal parameter number in definition of \fst. <to be read again> \i".

\documentclass{article}

\newcommand*{\newproj}[3]{%
  \newcommand*#1[#2]{%
    \expandafter###3%
  }%
}

\def\i{1}
\newproj{\fst}{2}{\i}
\newproj{\snd}{2}{2}

\begin{document}
\begin{tabular}{ll}
\verb^\fst{x}{y}^:& \fst{x}{y} \\
\verb^\snd{x}{y}^:& \snd{x}{y}
\end{tabular}
\end{document}
share|improve this question
    
Just omit the \expandafters: \newcommand*{\newproj}[3]{\newcommand*#1[#2]{###3}} does the job. –  Hendrik Vogt Feb 21 '13 at 20:02
    
@HendrikVogt Thanks; it works great! I've extended the question slightly to include the case where a macro is used to select the parameter. Do you have any ideas for that case? –  Henry DeYoung Feb 21 '13 at 20:29
    
Consider doing this with a loop: \foreach \x/\y/\z in {fst/2/\i,snd/2/2}{<do something>}. –  Ahmed Musa Feb 21 '13 at 21:43
    
@AhmedMusa How does the loop help with defining \newproj? –  Henry DeYoung Feb 21 '13 at 21:47

3 Answers 3

up vote 5 down vote accepted

enter image description here

You just want to fully expand both arguments using \number to get their decimal expansion, while avoiding expanding everything else (for which a toks register is useful)

\documentclass{article}

\newcommand*{\newproj}[3]{%
  \toks0{\newcommand*#1}%
  \edef\tmp{\the\toks0[\number#2]{####\number#3}}%
\tmp
  }

\def\i{1}
\newproj{\fst}{2}{\i}
\newproj{\snd}{2}{2}

\begin{document}
\begin{tabular}{ll}
\verb^\fst{x}{y}^:& \fst{x}{y} \\
\verb^\snd{x}{y}^:& \snd{x}{y}
\end{tabular}
\end{document}
share|improve this answer
    
Always something to learn from your answers. :) –  A.Ellett Feb 21 '13 at 20:51
    
Not sure I understand. Why doesn't something like \newcommand*{\newproj}[3]{\newcommand*#1[#2]{\expandafter##\number#3}} work? –  Henry DeYoung Feb 21 '13 at 21:21
    
@HenryDeYoung Because with \newproj{\fst}{2}{1} you would be doing \newcommand*\fst[2]{\expandafter#\number1} which is illegal. –  egreg Feb 21 '13 at 21:26
    
@egreg So, even though ## can be dealt with at expansion time, the other #s (such as #\number) must be dealt with at definition time (and therefore can't be postponed using \expandafter). Is that correct? –  Henry DeYoung Feb 21 '13 at 21:53
    
I think you have that backwards # (and only #) is handled specially at the point of definition. The rest of the tokens in the definition are just saved and then processed once the macro is expanded. # must be followed by # or a digit so #\number is a syntax error and prevents the definition at all. –  David Carlisle Feb 21 '13 at 21:55

Here's a start at something

\documentclass{article}
\newcommand{\newproj}[3]{%
    \expandafter\newcommand\csname #1\expandafter\endcsname[#2]{###3}
}
\pagestyle{empty}
\begin{document}

Hello

\newproj{helloworldapplesauce}{4}{3}

\helloworldapplesauce{a}{b}{c}{d}
\end{document}

Alternatively you might try to do (following the advice of @HendrikVogt )

\newcommand{\newproj}[3]{\newcommand{#1}[#2]{###3}}

should also do the trick

Regardless of the approach, you'll probably want to make sure that the values passed in the parameters are numbers and that whatever is passed in the third argument defining the function is no larger than the second.

share|improve this answer
    
Thanks; this works, but I'd like to understand why. I would have thought that ###3 would refer to the third argument of a doubly nested command. –  Henry DeYoung Feb 21 '13 at 20:08
    
In David Salomon's The Advanced TeXbook page 126, he explains that ###1 is the same as ## #1 where the ## expands to #. He references pg 203 of Knuth where it is explained a bit further. –  A.Ellett Feb 21 '13 at 20:15
    
Thanks; it works great! I've extended the question slightly to include the case where a macro is used to select the parameter. Do you have any ideas for that case? –  Henry DeYoung Feb 21 '13 at 20:30
\documentclass[12pt]{article}
\usepackage{catoptions}
\makeatletter
% \generateparams is not any costlier than using \newcommand:
\new@def*\generateparams#1#2{%
  \ifnum#1<\numexpr#2+1####\number#1%
    \expandafter\generateparams
    \expandafter{\number\numexpr#1+1\expandafter}%
    \expandafter{\number#2\expandafter}%
  \fi
}
\robust@def*\newproj#1#2#3{%
  \@ifdefinable#1\relax
  \cptexpanded{\def\noexpand#1\generateparams1{#2}{#####3}}%
}

% Examples of \newproj:
\def\one{1}
\newproj{\fst}{2}{\one}
\newproj{\snd}{2}{2}

% Using a loop to avoid repeating \newproj for every new definition:
\robust@def*\NewProj#1{%
  \cptforeach \x/\y/\z \in#1\do{%
    \cptexpandsecond\newproj{\noexpandcsn{\x}{\y}{\z}}%
  }%
}

% Examples of \NewProj:
\NewProj{fstb/2/\one, sndb/2/2}

\makeatother

% Let us print the examples:
\begin{document}
\begin{tabular}{ll}
\verb^\fst{x}{y}^:& \fst{x}{y} \\
\verb^\snd{x}{y}^:& \snd{x}{y} \\
\verb^\fstb{x}{y}^:& \fstb{x}{y} \\
\verb^\sndb{x}{y}^:& \sndb{x}{y}
\end{tabular}
\end{document}

enter image description here

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.