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.
\documentclass[pstricks,border=12pt]{standalone}
\usepackage{pst-node}
\begin{document}
\begin{pspicture}[showgrid](-5,-5)(5,5)
    \pnodes{A}(-2,3)(3,4)(2,-1)(-2,-4)(-4,0)
    \def\points{(0,0)}
    \foreach \x in {0,1,...,4}{%
            \pscircle*[linecolor=blue](A\x){3pt}%
            \xdef\points{\points+.2(A\x)}%
    }
    %The first line below causes errors.
    %\expandafter\nodexn{\points}{B}
    %\pscircle*[linecolor=red](B){3pt}
\end{pspicture}
\end{document}

How do I have to invoke \expandafter for a macro with multiple arguments?

share|improve this question
3  
Does \expandafter\nodexn\expandafter{\points}{B} work? You're just expanding the { token (which stays {). The LaTeX kernel also defines \@expandtwoargs which would \edefs the first two arguments of a macro: \@expandtwoargs\nodexn{\points}{B}. –  Qrrbrbirlbel Sep 17 '13 at 13:42
    
@Qrrbrbirlbel: Yes. It works. Thank you! Now, what do I have to do? Delete this question or wait for your answer and then accept it? –  Please don't touch Sep 17 '13 at 13:43
1  
Don't forget this trick if the argument you want to expand is at the end of a long list. Just \def the list up to that point, and expandafter the \def and following {: \documentclass{article} \usepackage[T1]{fontenc} \newcommand\manyargs[4]{#1.#2.#3.\detokenize{#4}} \def\expandthis{EXP} \begin{document} \manyargs{a}{b}{c}{\expandthis} \def\tmp{\manyargs{a}{b}{c}} \expandafter\tmp\expandafter{\expandthis} \end{document} I learned that from David Carlisle. –  Steven B. Segletes Sep 17 '13 at 13:51
    
@StevenB.Segletes I hope you don't mind that I have included your (or David's) trick in my answer. I've learned it by reading many sources where similar expansion tricks are often used. –  Qrrbrbirlbel Sep 17 '13 at 14:17
1  
with the pst-node.tex from texnik.dante.de/tex/generic/pst-node you can simply write \nodexn{\points}{B} without any \expandafter –  Herbert Sep 17 '13 at 18:23

3 Answers 3

up vote 13 down vote accepted

You need to do

\expandafter\nodexn\expandafter{\points}{B}

you need to "jump over" the { too otherwise

\expandafter\nodexn{\points}{B}

just expands { once (to {) before \nodexn gets expanded.

The LaTeX kernel defines a helpful macro \@expandtwoargs as

\def\@expandtwoargs#1#2#3{%
  \edef\reserved@a{\noexpand#1{#2}{#3}}\reserved@a}

which \edefs the first two arguments of a macro before "executing" it. Obviously, you would want to do something like

\makeatletter
\let\expandtwoargs\@expandtwoargs
\makeatother

to be able to use it comfortably. (And of course, this doesn't work for arguments that are not safely fully expandable.)

If you want to expand more than two arguments you can use a temporary macro which contains only the arguments:

\edef\tmp{{\argumentA}{\argumentB}{\argumentC}{\argumentD}}

which then only needs to be expanded once:

\expandafter\myMacro\tmp % \tmp already contains the braces

From the same trick box, but quite the opposite problem, namely to expand an argument at the end of a macro with many arguments, can be solved by stuffing everything up to the argument in a temporary macro which than can be "jumped over" very easily:

\def\B{B}
\def\tmp{\myMacro{argument A}{argument B}}
\expandafter\tmp\expandafter{\argumentC}

Otherwise you would need to do

\expandafter\myMacro\expandafter{\expandafter a\expandafter r\expandafter g …
share|improve this answer
    
One more question based on my answer here (locate the first code snippet at the top): Why don't I need \expandafter when invoking \pstHomO even though I use \Points as an argument? –  Please don't touch Sep 17 '13 at 14:32
    
Does that mean you can just drop the braces, i.e. that \expandafter\nodexn\points{B} would also work? –  Jonathan Sep 17 '13 at 19:11
1  
@Jonathan No, as \nodexn would than only grab the first two token of the expansion of \points (( and 0) as its arguments instead of the expansion of \points as the first and B as the second argument. –  Qrrbrbirlbel Sep 18 '13 at 11:17
    
@PGFTricks Unfortunately, I don’t know the exact syntax of \pstHomO (or what it actually does), but \Points only contains a list of things without =. Observe what happens if you do \edef\Points{\Points,A2=1} directly before \pstHomO and compare with \pstHomO[…]{O}{\Points,A2=1} (even though the =1 is thrown away anway). The = is not properly parsed in the first case but in the second. (You may fix this with the following redefinition: \def\@List#1{\xdef\@NewList{none}\expandafter\@List@i#1,\@nil\ignorespaces}.) –  Qrrbrbirlbel Sep 18 '13 at 11:31

This is a comment on the more general topic raised in Qrrbrbirlbel's answer of selectively expanding one argument of a macro before executing the macro itself. I will take here "expanding" as meaning expanding once, and it is not assumed that the arguments are only single tokens (the expansion will be applied only to the first token of the argument; this could provoke further expansions among this argument of course). My comment is that it is possible to do this expandably.

Nota Bene: a more powerful such "expandable expander" has been added in an edit, below. It also expands only once the (first token of the) targeted argument but this can be promoted to a "full expansion". (see code)

We need these utilities:

\def\expandArg #1#2{\expandafter\expandArgaux\expandafter{#2}{#1}}
\def\expandArgaux #1#2{#2{#1}}

Then imagine I need to have the 3rd of the 5 arguments to \mymacro be expanded once before the execution of \mymacro:

\expandArg {\mymacro {Not me}{Not me}}{Expand Me}{Not me}{Not me} 

does the trick. The difference with the trick mentioned in Qrrbrbirlbel's answer and in comments is that this is expandable in the sense of not needing a \def.

To illustrate:

\def\expandArg #1#2{\expandafter\expandArgaux\expandafter{#2}{#1}}
\def\expandArgaux #1#2{#2{#1}}

\tt
\def\mymacro #1#2#3#4#5{\meaning #3}
\def\x {\y}
\def\y {z}
\mymacro {1}{2}{\x}{4}{5}
\par
\expandArg {\mymacro {1}{2}}{\x}{4}{5}
\bye

Output:

expansion-trick

I mentioned in a comment that it was also possible to have the more user-friendly syntax:

\ExpandNth {5}\mymacro{A}{B}{C}{D}{E}{F}{G}

without extra braces, thus, to expandably expand the fifth argument only, prior to the execution of \mymacro.

Here is one way. It acts correctly if given an N zero or less, but will create errors if N exceeds the actual number of arguments. It is also crucial that no spaces are left in-between the arguments of the macro \mymacro to which the expandable expander is applied.

\catcode`\_ 11

\def\ExpandNth #1%
{%
    \romannumeral0\ifnum #1>0
      \expandafter\ExpandNth_a
    \else
      \expandafter\ExpandNth_none
    \fi {#1}%
}
\def\ExpandNth_none #1{ }
\def\ExpandNth_a #1#2{\ExpandNth_b {#1}{#2}}
\def\ExpandNth_b #1%
{%
    \ifnum #1>1
      \expandafter\ExpandNth_c
    \else
      \expandafter\ExpandNth_w
    \fi {#1}%
}
\def\ExpandNth_c #1#2#3%
{%
    \expandafter\ExpandNth_b\expandafter
        {\the\numexpr #1-1}{#2{#3}}%
}%
\def\ExpandNth_w #1#2#3%
{%
    \expandafter\ExpandNth_z\expandafter {#3}{#2}%
}%
% replace #3 above by \romannumeral-`0#3 for "full" expansion

\def\ExpandNth_z #1#2{ #2{#1}}%

\catcode`\_ 8       

\tt

\def\mymacro #1#2#3#4#5{\meaning #1\par
                        \meaning #2\par
                        \meaning #3\par
                        \meaning #4\par
                        \meaning #5\par}
\def\a{\A} \def\A{A}
\def\b{\B} \def\B{B}
\def\c{\C} \def\C{C}
\def\d{\D} \def\D{D}
\def\e{\E} \def\E{E}

\hsize 12cm

Original \string\mymacro:\par
\mymacro \a\b\c\d\e

\medskip\hrule\medskip

With prior (once) expansion of the first argument:\par
\ExpandNth {1}\mymacro \a\b\c\d\e

\medskip\hrule\medskip

With prior (once) expansion of the second argument:\par
\ExpandNth {2}\mymacro \a\b\c\d\e

\medskip\hrule\medskip

With prior (once) expansion of the third argument:\par
\ExpandNth {3}\mymacro \a\b\c\d\e

\medskip\hrule\medskip

With prior (once) expansion of the fourth argument:\par
\ExpandNth {4}\mymacro \a\b\c\d\e

\medskip\hrule\medskip

With prior (once) expansion of the fifth argument:\par
\ExpandNth {5}\mymacro \a\b\c\d\e

\bye

Output:

selective expansion

share|improve this answer
    
The user must be careful not to leave a space after {\x} in the \expandArg application above. We could define \expandArg with 3 arguments, and then the input would be \expandArg {\mymacro ...}{Expand me}{all the rest} and spaces would be allowed either before or after the {Expand me}. –  jfbu Sep 17 '13 at 15:09
    
It would also be possible to construct a \ExpandNth {n} such that \ExpandNth {5}\mymacro{A}{B}{C}{D}{E}{F}{G} expands the fifth argument, with no need for the user to put extra braces,; still working "expandably". But this is more complicated. –  jfbu Sep 17 '13 at 15:13
    
Code has been edited to implement the macro mentioned in my previous comment. –  jfbu Sep 17 '13 at 15:51
    
When I say that for N>#args errors are created this is not systematic: the effect is to expand the Nth token or braced material found and to reinject it within braces; and all those tokens in-between the last argument of the macro and the Nth spot will end up (each) in braces (or left unchanged if it was already {..} material). –  jfbu Sep 17 '13 at 17:30

For this particular application you can simply do

\newcommand{\nodexnX}[1]{\expandafter\nodexn\expandafter{#1}}

and call \nodexnX{\points}{B}

Or you can go further and redefine \nodexn so that it fully expands its first argument

\let\PSTRICKSnodexn\nodexn
\renewcommand{\nodexn}[1]{%
  \begingroup\edef\x{\endgroup
  \noexpand\PSTRICKSnodexn{#1}}\x
}

The LaTeX3 kernel has \exp_args:Nx that's implicitly added with \cs_generate_variant:Nn:

\usepackage{expl3}
\ExplSyntaxOn
\cs_set_eq:NN \pgftricks_nodexn:nn \nodexn
\cs_generate_variant:Nn \pgftricks_nodexn:nn { x }
\cs_set_eq:NN \nodexn \pgftricks_nodexn:xn
\ExplSyntaxOff

If you need to fully expand also the second argument, you can do

\cs_set_eq:NN \pgftricks_nodexn:nn \nodexn
\cs_generate_variant:Nn \pgftricks_nodexn:nn { xx }
\cs_set_eq:NN \nodexn \pgftricks_nodexn:xx

In both case you have effectively redefined \nodexn to expand its argument(s) before the original macro is called.

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.