![原始问题](https://linux22.com/image/263439/%E5%8E%9F%E5%A7%8B%E9%97%AE%E9%A2%98.png)
原始问题
我想创建一个元命令来创建新的投影命令。具体来说,\newproj{\cmd}{<n>}{<m>}
应该创建\cmd
一个新的<n>
(强制)参数命令,该命令始终扩展到第<m>
th 个参数。
例如,如果我们有\newproj{\fst}{2}{1}
和\newproj{\snd}{2}{2}
,那么\fst{x}{y}
应该扩展为,x
而\snd{x}{y}
应该扩展为y
。
以下是我的尝试:
\documentclass{article}
\newcommand*{\newproj}[3]{%
\newcommand*#1[#2]{%
\expandafter#\expandafter##3%
}%
}
\newproj{\fst}{2}{1}
\newproj{\snd}{2}{2}
\begin{document}
\begin{tabular}{ll}
\verb^\fst{x}{y}^:& \fst{x}{y} \\
\verb^\snd{x}{y}^:& \snd{x}{y}
\end{tabular}
\end{document}
不幸的是,这会出现错误“定义中的参数编号非法” \newproj
。
<to be read again> \expandafter
如何将参数用作某些整数或元参数的函数?
扩展问题:通过宏间接调用
A.Ellett 和 Hendrik Vogt 建议使用\newcommand*#1[#2]{###3}
因为##
扩展为#
。如果将正整数作为 传递给 ,则此方法非常有效#3
!\newproj
但是,假设我将宏作为 传递给\newproj
。#3
如何使用宏扩展来动态选择参数?
例如,下面的代码应该能产生正确的结果。但是,它给出了错误“定义中的参数编号非法\fst
。 <to be read again> \i
”。
\documentclass{article}
\newcommand*{\newproj}[3]{%
\newcommand*#1[#2]{%
\expandafter###3%
}%
}
\def\i{1}
\newproj{\fst}{2}{\i}
\newproj{\snd}{2}{2}
\begin{document}
\begin{tabular}{ll}
\verb^\fst{x}{y}^:& \fst{x}{y} \\
\verb^\snd{x}{y}^:& \snd{x}{y}
\end{tabular}
\end{document}
答案1
您只想完全扩展两个参数以\number
获取它们的十进制扩展,同时避免扩展其他所有内容(对于这种情况,toks 寄存器很有用)
\documentclass{article}
\newcommand*{\newproj}[3]{%
\toks0{\newcommand*#1}%
\edef\tmp{\the\toks0[\number#2]{####\number#3}}%
\tmp
}
\def\i{1}
\newproj{\fst}{2}{\i}
\newproj{\snd}{2}{2}
\begin{document}
\begin{tabular}{ll}
\verb^\fst{x}{y}^:& \fst{x}{y} \\
\verb^\snd{x}{y}^:& \snd{x}{y}
\end{tabular}
\end{document}
答案2
这是开始
\documentclass{article}
\newcommand{\newproj}[3]{%
\expandafter\newcommand\csname #1\expandafter\endcsname[#2]{###3}
}
\pagestyle{empty}
\begin{document}
Hello
\newproj{helloworldapplesauce}{4}{3}
\helloworldapplesauce{a}{b}{c}{d}
\end{document}
或者您可以尝试这样做(按照@HendrikVogt 的建议)
\newcommand{\newproj}[3]{\newcommand{#1}[#2]{###3}}
也应该可以
无论采用哪种方法,您都可能需要确保传递到参数中的值是数字,并且传递到定义函数的第三个参数中的值不大于第二个参数。
答案3
\documentclass[12pt]{article}
\usepackage{catoptions}
\makeatletter
% \generateparams is not any costlier than using \newcommand:
\new@def*\generateparams#1#2{%
\ifnum#1<\numexpr#2+1####\number#1%
\expandafter\generateparams
\expandafter{\number\numexpr#1+1\expandafter}%
\expandafter{\number#2\expandafter}%
\fi
}
\robust@def*\newproj#1#2#3{%
\@ifdefinable#1\relax
\cptexpanded{\def\noexpand#1\generateparams1{#2}{#####3}}%
}
% Examples of \newproj:
\def\one{1}
\newproj{\fst}{2}{\one}
\newproj{\snd}{2}{2}
% Using a loop to avoid repeating \newproj for every new definition:
\robust@def*\NewProj#1{%
\cptforeach \x/\y/\z \in#1\do{%
\cptexpandsecond\newproj{\noexpandcsn{\x}{\y}{\z}}%
}%
}
% Examples of \NewProj:
\NewProj{fstb/2/\one, sndb/2/2}
\makeatother
% Let us print the examples:
\begin{document}
\begin{tabular}{ll}
\verb^\fst{x}{y}^:& \fst{x}{y} \\
\verb^\snd{x}{y}^:& \snd{x}{y} \\
\verb^\fstb{x}{y}^:& \fstb{x}{y} \\
\verb^\sndb{x}{y}^:& \sndb{x}{y}
\end{tabular}
\end{document}
答案4
可以expl3
定义一个临时宏,并将所需的宏设置为等于它。什么都没有留下,因为我们在一个组中执行此操作并利用它\cs_new_eq:NN
(此处为\cs_new_eq:Nc
变体)进行全局定义。
我用来\prg_replicate:nn
构建所需数量的参数。
可能的变化:如果需要非长宏,则使用\cs_set_nopar:cx
而不是\cs_set:cx
。
两个参数都可以是宏或整型变量。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\newproj}{mmm}
{% #1 is the name of a command
% #2 is the number of arguments
% #3 is the argument to choose
\group_begin:
\tl_set:Nx \l_tmpa_tl { __deyoung_temp: \prg_replicate:nn { #2 } { n } }
\cs_set:cx { \l_tmpa_tl } { ## \int_eval:n { #3 } }
\cs_new_eq:Nc #1 { \l_tmpa_tl }
\group_end:
}
\ExplSyntaxOff
\newcommand\idx{1} \newcounter{baz} \setcounter{baz}{2}
\newproj{\fst}{2}{\idx}
\newproj{\snd}{2}{\value{baz}}
\begin{document}
\verb^\fst{x}{y}^: \fst{x}{y}
\verb^\snd{x}{y}^: \snd{x}{y}
Is it expandable? \edef\test{\fst{x}{y}}
\texttt{\meaning\test}
\newproj{\foo}{9}{4}\texttt{\meaning\foo}
\end{document}