amsmath 环境中无用的、误导性的错误

amsmath 环境中无用的、误导性的错误

环境简单equation

\documentclass{article}
\usepackage{amsmath}
\begin{document}
\begin{equation}
 a \foo b
\end{equation}
\end{document}

您可以看到一个有用的错误消息,像 Kile 这样的编辑者能够理解;

! Undefined control sequence.
l.5  a \foo
            b

制作报告5: Undefined control sequence a \foo

但如果你在 amsmath 环境中执行同样的事情,比如流行的align

\documentclass{article}
\usepackage{amsmath}
\begin{document}
\begin{align}
 a \foo b
\end{align}
\end{document}

你得到了无用的错误(并且它出现了两次);

! Undefined control sequence.
<argument>  a \foo 
                   b 
l.6 \end{align}

这使得 Kile 报告;6: Undefined control sequence \end{align}

检查日志非常繁琐而且最终没有意义,因为即使在日志中我也找不到包含未定义控制序列的实际行。 有没有什么方法可以阻止这种可怕的行为?

答案1

简单的回答:不。align环境的工作方式与 非常不同equation:在进行任何排版之前,必须读取所有材料。(从这个意义上讲,它类似于beamerframe环境,人们也会对此提出类似的问题。)在排版之前,必须读取要对齐的材料以进行测量,因此不能简单地“放弃”这一点。

答案2

在这两种情况下,未定义的命令都是错误消息后面行上的最后一个标记,这是此处记录的行为。

因此,问题不在于 TeX 或软件包,amsmath而在于 Kile 对日志文件的解析,根据您的描述,这似乎是错误的。也许您应该向编辑器提交错误报告。

请注意,行号必须是包含\end{align}未定义命令的行号,而不是包含未定义命令的行号,因为后者不可用。如果您转到

  \def\mycommand{..... \foo .....}

此时没有错误,但如果\mycommand使用,则您将收到未定义的命令\foo错误消息,显示行号\mycommand使用用过的\foo在其定义中未使用where 。

答案3

TeX 无法报告有关未定义控制序列的更多信息。假设以下示例:

\def\process#1{{\preprocess #1}}
\def\preprocess{\def\foo{Hello}}

\process{
  There is
  a text
  with \foo.
  More
  lines.
}

\let\preprocess=\relax

\process{
  There is
  a text
  with \foo.
  More
  lines.
}

\bye

第一次使用\process运行没有错误,第二次使用会出现错误:

! Undefined control sequence.
<argument>  There is a text with \foo 
                                      . More lines. 
\process #1->{\preprocess #1
                            }
l.20 }

您会发现,TeX 无法检查扫描参数中的所有控制序列是否在扫描期间和使用该参数之前都已定义。在使用参数之前,可以在宏的深处更改控制序列的含义。

当然,错误消息“未定义的控制序列”可以包含打印本身有问题的控制序列,但这样的消息格式与 TeX 报告的其他错误消息格式相悖。TeX 坚持以下原则:所有错误消息都保持统一的风格。

如果使用日志扫描器,其他一切都是日志扫描器的问题。

答案4

正如其他答案中所解释的那样,错误的原因在于它align不是一个“真实”的环境,而是将环境主体作为⟨参数⟩,从而丢失了行号信息,如“宏的行号未显示”部分中所述我对“ \errorcontextlines 有什么作用?”问题的回答

如果仅用于调试目的,您可以使用一些小技巧以align不测量其内容的方式重新实现环境等:

%! TEX program = lualatex
\documentclass{article}
\usepackage{amsmath}
%\usepackage{lua-visual-debug}
\begin{document}

\ExplSyntaxOn

%\iffalse

\cs_if_exist:NF \RenewEnvironmentCopy {  % https://tex.stackexchange.com/a/680717/250119 and https://tex.stackexchange.com/a/680721/250119
\NewDocumentCommand \RenewEnvironmentCopy {mm} {
    \expandafter \RenewCommandCopy \csname#1\expandafter\endcsname \csname#2\endcsname
    \expandafter \RenewCommandCopy \csname end#1\expandafter\endcsname \csname end#2\endcsname
}
}

% this can also be implemented with tabular and https://tex.stackexchange.com/q/112576/250119
\RenewDocumentEnvironment{split}{}{
  \let \\ \cr
  \vbox\bgroup
    \halign\bgroup
      & \hfill $\displaystyle ##$ & $\displaystyle {}##$ \hfill \cr
}{
      \crcr
    \egroup
  \egroup
}

\RenewDocumentEnvironment{multline}{}{
  \par

  \lineskip=3pt
  \leftskip=0pt
  \rightskip=0pt plus 1fil
  \parindent=0pt
  \parfillskip=0pt
  \def \\ {
    $  \par
    \leftskip=0pt plus 1fil
    $\displaystyle {}
  }
  $\displaystyle {}
}{
  $    \rightskip=0pt  \par
  \endcenter
}

\RenewDocumentEnvironment{gather*}{}{
  \par

  \lineskip=3pt
  \leftskip=0pt plus 1fil
  \rightskip=0pt plus 1fil
  \parindent=0pt
  \parfillskip=0pt
  \def \\ { $  \par  $\displaystyle }
  $\displaystyle
}{
  $  \par
}
\RenewEnvironmentCopy{gather}{gather*}

\RenewDocumentEnvironment{align*}{}{
  \lineskip=3pt
  $$
  \vbox\bgroup
    \let \\ \cr
    \tabskip=0pt plus 1fil
    \halign to \linewidth\bgroup
      &
        \tabskip=0pt
        \hfil $\displaystyle ##$
      &
        $\displaystyle {}##$ \hfil
        \tabskip=0pt plus 1fil
      \cr
}{
      \crcr
    \egroup
  \egroup$$
}
\RenewEnvironmentCopy{align}{align*}

\RenewDocumentEnvironment{flalign*}{}{
  $$
  \vbox\bgroup
    \let \\ \cr
    \tabskip=0pt
    \halign to \linewidth\bgroup
      &
        \tabskip=0pt
        \hfil $\displaystyle ##$
      &
        $\displaystyle {}##$ \hfil
        \tabskip=0pt plus 1fil
      \cr
}{
      \crcr
    \egroup
  \egroup$$
}
\RenewEnvironmentCopy{flalign}{flalign*}

\use_none:n \fi
\ExplSyntaxOff

\begin{equation*}
a=b
\end{equation*}
\begin{equation}
a=b
\end{equation}
\begin{equation}\label{xx}
\begin{split}
a& =b+c-d\\
& \quad +e-f\\
& =g+h\\
& =i
\end{split}
\end{equation}
\begin{multline}
a+b+c+d+e+f\\
+i+j+k+l+m+n
\end{multline}
\begin{multline}
a+b+c+d+e+f\\
a+b+c+d+e+f\\
+a+b+c+d+e+f\\
+i+j+k+l+m+n
\end{multline}
\begin{gather}
a_1=b_1+c_1\\
a_2=b_2+c_2-d_2+e_2
\end{gather}
\begin{align}
a_1& =\frac{1}{2} b_1+c_1\\
a_2& =b_2+c_2-d_2+e_2
\end{align}
\begin{itemize}
  \item The formula is
    \begin{align}
a_1& =\frac{1}{2} b_1+c_1\\
a_2& =b_2+c_2-d_2+e_2
\end{align}
some more text.
\end{itemize}
\begin{align}
a_{11}& =b_{11}&
a_{12}& =b_{12}\\
a_{21}& =b_{21}&
a_{22}& =b_{22}+c_{22}
\end{align}
\begin{flalign*}
a_{11} + b_{11}& = c_{11}&
a_{12}& =b_{12}\\
b_{21}& = c_{21}&
a_{22}& =b_{22}+c_{22}
\end{flalign*}

\end{document}

当然,这个实现的输出质量是无可比拟的,但它保留了错误消息中的行号以及同步信息。对于草稿编译/调试,我认为它可能很有用。

注意:这没有经过很好的测试。它可能会产生原始环境不会产生的其他错误。

为了比较输出质量(它是应该是坏的!请勿在最终文档中使用):

输出

左边是正常输出,右边是经过破解的输出。(您还可以注意到缺少标签编号)


考虑到 amsmath 对其内容的复杂处理,我认为进行多次测量是必需的

amsmath 功能的详细信息:

amsmath 源文档片段

不过我能想到两种解决方法:


目前,使用这个想法其他使用我的包进行黑客攻击是可能的cprotectinside

%! TEX program = lualatex
\documentclass{article}
\usepackage{amsmath}
\usepackage{cprotectinside}
\cprotectinsideEnableSyncInner
\begin{document}

\errorcontextlines=10

\cprotectinside{|}{
\begin{align}
|%
a_{11}& =b_{11}&
a_{12}& =b_{12}\\
a_{21}& =b_{21}&
a_{22}& =b_{22}+c_{22}
|
\end{align}
}

\end{document}

(如果使用 lualatex,它还会保留 synctex,并且错误消息至少指向正确的线,尽管文件名可能有点混乱。请注意,它需要 GitHub 上的新版本,该版本未在 CTAN 上发布)

相关内容