为什么这种使用 `\expandafter` 的方式不起作用?

为什么这种使用 `\expandafter` 的方式不起作用?

我写了以下代码:

\newif\ifconsecutive
\consecutivefalse

\newcommand{\myfirst}[1]{#1\consecutivetrue\expandafter\consecutivefalse}
\newcommand{\mysecond}[1]{\ifconsecutive $\longrightarrow$\fi #1}

我的想法是,如果我写

\myfirst{A}\mysecond{B}

我得到的相当于

A $\longrightarrow$ B

而如果我在中间输入一些内容,比如

\myfirst{A} then \mysecond{B}

我得到的却是

A then B

这个想法是,在有效时,\expandafter会导致调用之后的文本\myfirst(调用\mysecond或一些任意其他代码)被扩展,因此如果接下来是调用,则将执行并生成箭头,而如果后面还有其他内容,则不会关心。在扩展之后,应该被调用,导致任何后续的调用\consecutivetrue\mysecond\ifconsecutive\consecutivetrue\consecutivefalse\mysecond都不会生成箭头。

然而什么实际上发生的情况是,无论宏是否连续,箭头都永远不会插入。

现在我的问题是:为什么这对宏不能按预期工作?

以下是完整的可编译代码:

\documentclass{article}

\newif\ifconsecutive
\consecutivefalse
\newcommand{\myfirst}[1]{#1\consecutivetrue\expandafter\consecutivefalse}
\newcommand{\mysecond}[1]{\ifconsecutive $_$\fi #1}

\begin{document}
\myfirst{A}\mysecond{B}

\myfirst{A} then \mysecond{B}
\end{document}

答案1

您不仅想扩展\mysecond,还想扩展结果,因此您需要在前面\ifconsecutive加上三个标记。\expandafter\consecutivefalse

\documentclass{article}

\newif\ifconsecutive
\consecutivefalse
\newcommand{\myfirst}[1]{#1\consecutivetrue\expandafter\expandafter\expandafter\consecutivefalse}
\newcommand{\mysecond}[1]{\ifconsecutive ${}\to\nobreak{}$\fi #1}

\begin{document}
\myfirst{A}\mysecond{B}

\myfirst{A} then \mysecond{B}
\end{document}

在此处输入图片描述

但是,我不推荐这种上下文相关的宏。

一个不同的策略是使用,提供的\new@ifnextchar版本不会吞噬或忽略空格:\@ifnextcharamsmath

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\newcommand{\myfirst}[1]{#1\new@ifnextchar\mysecond{${}\to\nobreak{}$}{}}
\newcommand{\mysecond}[1]{#1}

\begin{document}
\myfirst{A}\mysecond{B}

\myfirst{A} \mysecond{B}

\myfirst{A} then \mysecond{B}

\myfirst{A}\relax\mysecond{B}
\end{document}

在此处输入图片描述

答案2

替代:

\documentclass{article}
\newcommand\mycmd[3][$\longrightarrow$]{#2 #1 #3}
\begin{document}    
\mycmd{A}{B}

\mycmd[then]{A}{B}

\end{document}

也可以将命令定义为\mycmd{A}[then]{B}

相关内容