How does your mind bend \expandafter to its will?

\in@{\foo}{\cslist} % <--- What combination of \expandafter is needed here?

If \foo is first expanded, then we have the problem, that \expandafter cannot jump over serveral tokens at once, also the number of tokens is not known. Therefore the latest token is expanded first. But at this stage we cannot add the \expandafter, because we have to insert the \expandafter tokens for \foo first:

\ex\in@\ex{\foo}{\cslist}

Then we add the outmost \expandafter chain to expand \cslist. The next line uses \EX for the new \expandafter to make the difference between the stages visible:

\EX\ex\EX\in@\EX\ex\EX{\EX\ex\EX\foo\EX}\EX{\cslist}

Result:

\ex\ex\ex\in@\ex\ex\ex{\ex\ex\ex\foo\ex}\ex{\cslist}

A more generic algorithm would be:

  1. Establish an order of expansions:

    • Collapsing expansions: We have to make sure, that the number of tokens is known and we can insert \expandafter between them, if we need to jump over them. Therefore constructs like \csname need to be expanded at an earlier level. This allows also the use of arguments inside \csname with an unknown number of tokens, because the \csname construct becomes one single command token after one expansion step.

      Note: See also the trick below, that \csname can be used to expand stuff afterwards.

    • Expanding expansions, e.g. \cslist above, on the right side have to come first, because we cannot jump over a unknown number of tokens.

  2. Now we can add \expandafter chains from the start to the token that needs expanding. The order from the previous step is now reversed. First the chain for the token that is last expanded is inserted, e.g.:

    0. \a\b\last\c\first
    1. \EX\a\EX\b\last\c\first % \EX inserted
    

    Then we go backwards in time to expand the token that needs expansion before the last:

    =1. \ex\a\ex\b\last\c\first
     2. \EX\ex\EX\a\EX\ex\EX\b\EX\last\EX\c\first % \EX inserted
    =2. \ex\ex\ex\a\ex\ex\ex\b\ex\last\ex\c\first
    

"Tricks"

Sometimes TeX helps to save some \expandafter.

  • Expanding after \csname:

    Let's assume \foo and \cslist are not given explicitly but constructed via \csname:

    \in@{\csname foo\endcsname}{\csname cslist\endcsname}
    

    A naive approach would require four expansions waves:

    1. expanding the first \csname to get one token \foo
    2. expanding the second \csname to get \cslist
    3. expanding \cslist
    4. expanding \foo

    Result: Start with 24-1 \expandafter (= 15).

    This can be reduced: TeX expands the tokens between \csname and \endcsname until nothing expandable is left to form a command sequence. The following uses this to get \cslist and its expansion before \foo is constructed:

    \csname foo\ex\ex\ex\endcsname
    \ex\ex\ex}\ex\ex\ex{\csname cslist\endcsname}
    

    And the whole expression with the expansion of \foo:

    \ex\ex\ex\in@\ex\ex\ex{\csname foo\ex\ex\ex\endcsname
    \ex\ex\ex}\ex\ex\ex{\csname cslist\endcsname}
    

    The result are 15 \expandafter in total.

  • Expanding arguments of some TeX primitives such as \uppercase.

    Let's assume \foo expands to a word that should be converted to uppercase:

    \ex\uppercase\ex{\foo}
    

    Here we can save the first \expandafter, because \uppercase already expands the next tokens until it gets the opening brace:

    \uppercase\ex{\foo}
    

    Other primitives: \detokenize, \scantokens, \message.

    Caveat: If someone redefines \uppercase as macro, this trick will fail obviously.


You can exploit \unexpanded:

\documentclass{article}

\makeatletter
% both arguments are expanded once
\newcommand{\xxin@}[2]{%
  \begingroup\edef\x{\endgroup
    \noexpand\in@{\unexpanded\expandafter{#1}}{\unexpanded\expandafter{#2}}%
  }\x
}
% the first argument is expanded once
\newcommand{\xnin@}[2]{%
  \begingroup\edef\x{\endgroup
    \noexpand\in@{\unexpanded\expandafter{#1}}{\unexpanded{#2}}%
  }\x
}
% the second argument is expanded once
\newcommand{\nxin@}[2]{%
  \begingroup\edef\x{\endgroup
    \noexpand\in@{\unexpanded{#1}}{\unexpanded\expandafter{#2}}%
  }\x
}
\makeatletter

\begin{document}
\makeatletter
\def\foo{foo}
\def\cslist{foo,bar,baz}

\in@{foo}{foo,bar,baz}
\ifin@ true\else false\fi

\xnin@{\foo}{foo,bar,baz}
\ifin@ true\else false\fi

\nxin@{foo}{\cslist}
\ifin@ true\else false\fi

\xxin@{\foo}{\cslist}
\ifin@ true\else false\fi

\makeatother
\end{document}

This prints “true” for all cases.


The mandatory LaTeX3 solution, where \tl_if_in:nnTF (with variants) is provided.

\documentclass{article}
\usepackage{expl3}
\ExplSyntaxOn
\cs_generate_variant:Nn \tl_if_in:nnTF { oo }
\ExplSyntaxOff

\begin{document}

\def\foo{foo}
\def\cslist{foo,bar,baz}

\ExplSyntaxOn
\tl_if_in:nnTF{foo,bar,baz}{foo}{true}{false}\par

\tl_if_in:noTF{foo,bar,baz}{\foo}{true}{false}\par

\tl_if_in:onTF{\cslist}{foo}{true}{false}\par

\tl_if_in:ooTF{\cslist}{\foo}{true}{false}\par
\ExplSyntaxOff
\end{document}

\in@{\foo}{\cslist}

If you don't need pure expansion and can afford an assignment, that can simplify things

\def\tmp{\expandafter\in@\expandafter{\foo}}
\expandafter\tmp\expandafter{\cslist}

only needs four \expandafter