我想构造一个命令,比如说\newlet
,我可以用它来做
\newlet\x\y
和/或
\newlet\x=\y
是\x
唯一的(即尚未使用)。
开始了
\protected\def\newlet#1{%
\@ifnextchar={\@firstoftwo{\@newlet{#1}}}{\@newlet{#1}}%
}
\def\@newlet#1{\@ifdefinable{#1}\relax\let#1= }
% Obviously works:
\newlet\sptoken=\@sptoken
% Obviously fails:
\newlet\sptoken\@sptoken
答案1
以一般方式处理空格很棘手。这里你需要一个预览和删除函数。这在 LaTeX3 中可用\peek_meaning_remove:NTF
,即 ,其中我会使用
\RequirePackage{expl3}
\ExplSyntaxOn
\cs_new_protected:Npn \newlet #1
{
\peek_meaning_remove:NTF =
{ \cs_new_eq:NN #1 }
{ \cs_new_eq:NN #1 }
}
\ExplSyntaxOff
\makeatletter
\newlet\sptoken=\@sptoken
当然,这可以用原语“写出”。忽略对标记的谨慎&
(使用附录 D 技巧),类似
\makeatletter
\protected\long\def\newlet#1{%
\protected\def\@newlet@fcommon{%
\ifdefined#1%
\expandafter\ERROR
\fi
\let#1=
}%
\let\@tempa= =%
\futurelet\@let@token\@newlet
}
\protected\def\@newlet{%
\ifx\@let@token\@tempa
\expandafter\@newlet@true
\else
\expandafter\@newlet@fcommon
\fi
}
\protected\def\@newlet@true{%
\afterassignment\@newlet@fcommon
\let\@temp@= %
}
将会起作用(它是 的简化版本,\peek_meaning_remove:NTF
分支是硬编码的)。特别要注意的是,=
使用 和 来删除\let
以\afterassignment
重新获得控制权,而不是使用参数。
这里的基本思想与 并无二致\@ifnextchar
,但不包括后者所包含的删除空格的循环。LaTeX3 包提供了“预打包”的两者(相当于\@ifnextchar
`\peek_meaning_remove_spaces:NTF)。
答案2
以下是约瑟夫赖特 (Joseph Wright) 想法的一个变体:
\protected\long\def\newlet#1{%
\def\@newlet##1{%
\ifdefined#1%
\@latex@error{Command '\string#1' already exists}\@ehc
\fi
\let#1=
}%
\futurelet\@let@token\@@newlet
}
\protected\def\@@newlet{%
\ifx\@let@token=%
\expandafter\@newlet
\else
\expandafter\@newlet\expandafter\relax
\fi
}
但它仍然失败了
\def\z#1{\newlet\y#1}\z{ }=\z