定义一个宏,该宏定义一个采用给定代码和参数的宏

定义一个宏,该宏定义一个采用给定代码和参数的宏

我有一个宏,它接受两个参数,一个名称和代码:

\newcommand\definesomething[2]{%
  \@namedef{something@#1}##1{#2}}
\definesomething{whatever}{Code with #1}
\show\something@whatever

这工作正常,但我想改变内部定义,因此定义一个宏,该宏使用给定的代码定义一个宏:

\newcommand\definesomething[2]{%
  \@namedef{something@#1}{%
    % ...
    \def\something##1{#2}%
    % ...
  }}
\definesomething{whatever}{Code with #1}
\show\something@whatever

显然这种方式行不通。但是如何正确地做到这一点(不使用xparse)?

当然我可以在这里使用辅助宏,但恕我直言,这远不是一个好的解决方案:

\newcommand\definesomething[2]{%
  \@namedef{something@@#1}##1{#2}% define helper macro
  \@namedef{something@#1}{%
    % ...
    \expandafter\let\expandafter\something\csname something@@#1\endcsname
    % ...
  }}
\definesomething{whatever}{Code with #1}
\show\something@whatever

有什么想法可以做得更好吗?

附录 2019-09-14:用户界面(\definesomething{whatever}{Code with #1})需要保持不变,我想摆脱\@namedef{something@@#1}每次使用时定义的额外辅助宏。如果只在使用后才定义\definesomething就好了。\something@whatever\definesomething{whatever}{...}

答案1

如果有 ε-TeX 扩展可用,那么您可以系统地嵌套\unexpanded在里面\edef

您可以实现序列

\definesomething{⟨MacroNamePart⟩}{⟨Code with #1⟩} → 定义 \something@MacroNamePart

\something@MacroNamePart → 定义 \something{#1} →Code with #1

如下:

\makeatletter
\newcommand\definesomething[2]{%
  \expandafter\edef\csname something@#1\endcsname{%
    \unexpanded{\def\something}####1\unexpanded{{#2}}%
  }%
}%

\show\definesomething
\definesomething{whatever}{Code with #1}%

\show\something@whatever
\something@whatever

\show\something

\stop

在此处输入图片描述

每个定义级别,其中用户级宏的参数的哈希值应加倍(以便在宏扩展期间它们可以减半)需要另一个嵌套级别\unexpanded

根据经验法则,唯一必须做的事情不是进入的是表示通过定义的宏\unexpanded中出现的参数的哈希和数字序列。⟨parameter texts⟩\edef

这些定义⟨balanced texts⟩中的 的嵌套括号也不需要放入,这使得生活变得简单。⟨definition texts⟩\edef\unexpanded

您可以轻松实现序列

\definesomething{⟨MacroNamePart⟩}{⟨Code with #1⟩} → 定义 \something@DefinitionNestLevelOne

\something@DefinitionNestLevelOne → 定义 \something@DefinitionNestLevelTwo

\something@DefinitionNestLevelTwo → 定义 \something@MacroNamePart

\something@MacroNamePart → 定义 \something{#1} →Code with #1

如下:

\makeatletter
\newcommand\definesomething[2]{% 
  \edef\something@DefinitionNestLevelOne{%<-opening brace of \edef-definition-text needs not be in \unexpanded
  % here things are surrounded by 1 \edef, thus everything that is not a parameter
  % of this one \edef must be nested in 1 level of \unexpanded:
    \unexpanded{\edef\something@DefinitionNestLevelTwo}{%<-opening brace of \edef-definition-text needs not be in \unexpanded
     % here things are surrounded by 2 \edef, thus everything that is not a parameter
     % of one of these 2 \edef must be nested in 2 levels of \unexpanded:
      \unexpanded{\unexpanded{\expandafter\edef\csname something@#1\endcsname}}{%<-opening brace of \edef-definition-text needs not be in \unexpanded
         % here things are surrounded by 3 \edef, thus everything that is not a parameter
         % of one of these 3 \edef must be nested in 3 levels of \unexpanded:
         \unexpanded{\unexpanded{\unexpanded{\def\something}}}################1\unexpanded{\unexpanded{\unexpanded{{#2}}}}% 
      }%<-closing brace of \edef-definition-text needs not be in \unexpanded
    }%<-closing brace of \edef-definition-text needs not be in \unexpanded
  }%<-closing brace of \edef-definition-text needs not be in \unexpanded
}%

\show\definesomething
\definesomething{whatever}{Code with #1}%

\show\something@DefinitionNestLevelOne
\something@DefinitionNestLevelOne

\show\something@DefinitionNestLevelTwo
\something@DefinitionNestLevelTwo

\show\something@whatever
\something@whatever

\show\something

\stop

在此处输入图片描述


如果没有 ε-TeX 扩展,您该怎么办?

在非常特殊的情况下,⟨Code with #1⟩只包含#1但不包含##1等,您可以使用它⟨Code with #1⟩来定义一个处理一个参数的宏,并使用多个哈希值作为参数来调用该宏来乘以哈希值。可能看起来像这样:

\makeatletter
\newcommand\definesomething[2]{%
  {%
    \def\tempa##1{\def\tempa{#2}}%
    \tempa{########1}%
    \expandafter
  }\expandafter\innerdefinesomething\expandafter{\tempa}{#1}%
}%

\newcommand\innerdefinesomething[2]{%
  \@namedef{something@#2}{%
    % ...
    \def\something####1{#1}%
    % ...
}}

\show\definesomething
\definesomething{whatever}{Code with #1}%

\show\something@whatever
\something@whatever

\show\something

\stop

答案2

我不确定我是否理解了这个问题,但也许:

> \something@whatever=macro:
->\def \something ##1{Code with ##1}.
l.12 \show\something@whatever

? 
> \something=macro:
#1->Code with #1.
l.16 \show\something

? 

\makeatletter

\newcommand\definesomething[2]{%
  \@namedef{something@#1}{%
    % ...
    \def\something####1{#2}%
    % ...
  }}

\definesomething{whatever}{Code with ##1}

\show\something@whatever

\something@whatever

\show\something

答案3

您可以#使用令牌寄存器将令牌加倍。但是,这需要在主定义主体中使用\edef和。\unexpanded

\makeatletter
\newcommand\definesomething[2]{%
  \toks@={#2}%
  \expandafter\edef\csname something@#1\endcsname{%
    % ...(all in \unexpanded)
    \def\noexpand\something####1{\the\toks@}%
    % ...(all in \unexpanded)
  }}
\definesomething{whatever}{Code with #1}
\show\something@whatever
\something@whatever
\show\something

控制台输出是

This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) (preloaded format=pdflatex)
 restricted \write18 enabled.
entering extended mode
(./as.tex
LaTeX2e <2018-12-01>
> \something@whatever=macro:
->\def \something ##1{Code with ##1}.
l.10 \show\something@whatever

? 
> \something=macro:
#1->Code with #1.
l.12 \show\something

相关内容