对在 foreach 循环中更新 newcommand 常量感到困惑

对在 foreach 循环中更新 newcommand 常量感到困惑

我对如何更新 \foreach 循环内的“常量”构造感到困惑,这里的类似问题并没有直接解决我所面临的问题,而且我还没有在 LaTeX 中进行足够的实验(还没有!;)来自己解决这个问题。

我认为问题出在 \const 定义上。我曾尝试用 \glet、\csglet、\gletcs 和 \csgletcs 替换 \global\edef(相当盲目,但这里的几个答案中都建议这样做),但无济于事。

我很感激任何关于此事的帮助,

谢谢!

\documentclass{article}

\usepackage{pgffor}
\usepackage[nomessages]{fp}

% ---- Helper function: easily add values to variables
%      Taken from a reply on stackoverflow that I can't find back...
%.     Works like so \const{VariableName}{value} ex: \const{CoolVariable}{5}
%.     and can then be called with \CoolVariable
%.     and can be updates with \const{CoolVariable}{CoolVariable+10}
\newcommand\const[3][0]{%
   \global\edef\temporary{round(#3}%
   \expandafter\FPeval\csname#2\expandafter\endcsname
       \expandafter{\temporary:#1)}%
}


% ---- Set dummy variable 
\const{MyVariable}{1}

% ---- I want to loop over a list of keywords with the name of "MyVariable"
%.     Only one here for example.
\newcommand\MyVariableList{MyVariable}

% ---- Start the loop and update values of constants in MyVariableList
\foreach \variable in \MyVariableList{
   % ---- This updates the variable \MyVariable correctly
   \const{\csname variable\endcsname}{\csname variable\endcsname +20}
   
   % ---- Values of \MyVariable changes within the loop
   MyVariable inside the loop: \csname \variable\endcsname
}

\begin{document}

MyVariable outisde the loop: 
% ---- But not outside of it 
\MyVariable

\end{document}

示例输出

答案1

\foreach将每次迭代放在一个组中。因此,您需要将变量的赋值设为全局变量。

以下用途xfp(因为我不知道如何使用来实现这一点fp)使分配变得全局化。

\documentclass{article}

\usepackage{pgffor}
\usepackage{xfp}

\newcommand\const[3][0]{%
  \xdef#2{\fpeval{round(#3,#1)}}%
}


% ---- Set dummy variable 
\const\MyVariable{1}

% ---- I want to loop over a list of keywords with the name of "MyVariable"
%.     Only one here for example.
\newcommand\MyVariableList{MyVariable}

\begin{document}
% ---- Start the loop and update values of constants in MyVariableList
\foreach \variable in \MyVariableList{%
   % ---- This updates the variable \MyVariable correctly
   \expandafter\const\csname\variable\endcsname{\csname\variable\endcsname +20}%
   % ---- Values of \MyVariable changes within the loop
   MyVariable inside the loop: \csname\variable\endcsname
}

MyVariable outside the loop: 
% ---- But not outside of it 
\MyVariable

\end{document}

另一种方法是使用不对迭代进行分组的循环。可以使用以下方法完成此操作\clist_map_inline:nn

\documentclass{article}

% get the function from expl3 and give it a document level name so that we can
% use it.
\ExplSyntaxOn
\cs_new_eq:NN \clistmap \clist_map_inline:nn
\ExplSyntaxOff

\usepackage[nomessages]{fp}

% ---- Helper function: easily add values to variables
%      Taken from a reply on stackoverflow that I can't find back...
%.     Works like so \const{VariableName}{value} ex: \const{CoolVariable}{5}
%.     and can then be called with \CoolVariable
%.     and can be updates with \const{CoolVariable}{CoolVariable+10}
\newcommand\const[3][0]{%
   \edef\temporary{round(#3}%
   \expandafter\FPeval\csname#2\expandafter\endcsname
       \expandafter{\temporary:#1)}%
}


% ---- Set dummy variable 
\const{MyVariable}{1}
\const{YourVariable}{2}

\begin{document}
% ---- Start the loop and update values of constants in MyVariableList
\clistmap{MyVariable, YourVariable}
  {%
    % #1 will be the current loop iterations element
    % ---- This updates the variable \MyVariable correctly
    \const{#1}{#1 + 20}%
    % ---- Values of \MyVariable changes within the loop
    #1 inside the loop: \csname #1\endcsname\par
  }

MyVariable outside the loop: 
% ---- But not outside of it 
\MyVariable
\YourVariable

\end{document}

答案2

\foreach每个循环都在一个组内进行。这是一个很常见的问题。

可以\global\edef始终对常量进行全局赋值。顺便说一句,代码中的使用是多余的。

\documentclass{article}

\usepackage{pgffor}
\usepackage[nomessages]{fp}

% ---- Helper function: easily set values to variables
\newcommand\const[3][0]{%
  \FPeval\temporary{round(#3:#1)}%
  \global\expandafter\let\csname #2\endcsname\temporary
}

% ---- Set dummy variable 
\const{MyVariable}{1}

% ---- I want to loop over a list of keywords with the name of "MyVariable"
%.     Only one here for example.
\newcommand\MyVariableList{MyVariable}

\begin{document}

% ---- Start the loop and update values of constants in MyVariableList
\foreach \variable in \MyVariableList{
   % ---- This updates the variable \MyVariable correctly
   \const{\csname variable\endcsname}{\csname variable\endcsname +20}
   
   % ---- Values of \MyVariable changes within the loop
   MyVariable inside the loop: \csname \variable\endcsname
}

MyVariable outside the loop: 
% ---- But not outside of it 
\MyVariable

\end{document}

在此处输入图片描述

我在这里展示了一种不同的方法,其中变量“按名称”调用,而不是使用笨拙的\csname<name>\endcsname

\documentclass{article}

\usepackage{xfp} % easier than fp

\ExplSyntaxOn

\NewDocumentCommand{\const}{O{0}mm}
 {
  % allocate a variable if not yet existing
  \fp_if_exist:cF { l_pimento_const_#2_fp }
   { \fp_new:c { l_pimento_const_#2_fp } }
  % set the value
  \fp_set:cn { l_pimento_const_#2_fp } { round(#3,#1) }
 }

\NewExpandableDocumentCommand{\eval}{m}
 {
  \fp_use:c { l_pimento_const_#1_fp }
 }

\NewDocumentCommand{\setconstants}{sO{0}mm}
 {
  \cs_set:Nn \__pimento_const_set:n { \const[#2]{##1}{#4} }
  \IfBooleanTF{#1}
   {
    \clist_map_function:NN #3 \__pimento_const_set:n
   }
   {
    \clist_map_function:nN { #3 } \__pimento_const_set:n
   }
 }

\ExplSyntaxOff

% ---- Set dummy variable 
\const{MyVariableA}{1}
\const{MyVariableB}{3}

\newcommand{\MyList}{MyVariableA,MyVariableB}

\begin{document}

\setconstants{MyVariableA,MyVariableB}{\eval{#1}+20}

\eval{MyVariableA}

\eval{MyVariableB}

\setconstants*[2]{\MyList}{\eval{#1}/2}

\eval{MyVariableA}

\eval{MyVariableB}

\fpeval{\eval{MyVariableA}+\eval{MyVariableB}}

\end{document}

其最大的优势在于fp操作可扩展。

在此处输入图片描述

相关内容