如何在不修改 \const 的实现的情况下使 \const{\length{\list}} 工作?

如何在不修改 \const 的实现的情况下使 \const{\length{\list}} 工作?

\const不适用于当前定义。它被定义为在 TeX 和 PostScript 范围内易于声明的常量。例如,如果我想定义一个Speed值的const 300000000,我可以使用在 PS 和 TeX 范围内已知的单个调用来声明它\const{Speed}{300000000}。另一个例子,如果我想NumberOfElements在 PS 和 TeX 范围内创建一个 const,我可以调用\const{NumberOfElements}{\length{\list}}where \length(定义如 MWE 中所示)和\def\list{a,b,c}

问题是我不懂创作\const{\length{\list}}作品时保持\const作品的初衷。这是 MWE。

\documentclass[pstricks,border=12pt]{standalone}

\usepackage{pstricks-add,fp}

% user defined data
\def\listX{1,2,3,4,5,6}
\def\listY{1,2,3}

% to determine the number of elements in a list
\newcounter{x}
\def\length#1{\setcounter{x}{0}\psforeach{\i}{#1}{\stepcounter{x}}\thex}


% to create constants in both TeX and PS scopes
\def\const#1#2{%
    \expandafter\FPeval\csname#1\endcsname{#2}%
    \pstVerb{/#1 \csname#1\endcsname\space def}%
}



\const{Nx}{\length{\listX}}
\const{Ny}{\length{\listY}}
\const{CellW}{1}
\const{CellH}{2}


\const{CanvasWidth}{Nx*CellW}
\const{CanvasHeight}{Ny*CellH}


\begin{document}

\begin{pspicture}[showgrid=bottom](\CanvasWidth,\CanvasHeight)
    % use other PS constants here
\end{pspicture}

\end{document}

附加问题:有没有更聪明的方法来了解列表中元素的数量?

答案1

让我们总体上看一下这个问题,尽管深入的讨论需要写很多页书。

您关心的是命令的定义,而不仅仅是嵌套宏调用。“工作”定义

\def\const#1#2{\expandafter\def\csname#1\endcsname{#2}}

通过电话

\const{Count}{\length{\list}}

相当于

\def\Count{\length{\list}}

如果你也有\def\list{1,2,3},那么

\const{Count}{\length{\list}}\Count

会打印 3。但是,如果你说

\def\list{1,2,3}
\const{Count}{\length{\list}}
\Count

\def\list{a,b,c,d}
\Count

你会得到

3
4

为什么?因为宏\Count是根据 定义的\list,它将使用 的当前含义\list,而不是定义时的含义:\list只是一个指向标记列表(当前替换文本)的指针。

\Count你的问题是将当前的的长度\list,与可能的后续重新定义无关。并且您希望它作为纯数字,因为您必须将其\pstVerb作为 PostScript 标记的替换文本传递给。

解决这个问题的方法是执行计算,将数字结果存储在临时控制序列中,然后使用\edef

这里有一种方法:

\makeatletter
\newcount\const@count
\def\length#1{%
  \const@count=\z@
  \@for\next:=#1\do{\advance\const@count\@ne}%
  \edef\@tempa{\number\const@count}%
}
\def\const#1#2{%
  #2%
  \expandafter\let\csname #1\endcsname\@tempa
  \begingroup\edef\x{\endgroup
    \noexpand\pstVerb{/#1 \@tempa\space def}}\x
}
\makeatother

称之为

\const{Count}{\length{\list}}

重要的是执行计算定义\Count并执行\pstVerb

这与您在其他地方所做的事情类似\FPeval

首先\length{\list}计算并将结果存储在中\@tempa\edef因此实际数字是替换文本。然后\let将使\Count具有当前含义,\@tempa然后\pstVerb以间接方式发出,以避免在替换文本中引用\@tempa,这要归功于\edef再次。


让我们尝试概括这一点;我建议使用三个参数的宏:

\makeatletter
\def\const#1#2#3{% #1=name, #2=method, #3=data
   #2{#1}{#3}%
   \begingroup\edef\x{\endgroup
     \noexpand\pstVerb{/#1 \csname#1\endcsname\space def}}\x
}
\newcount\const@count
\def\length#1#2{%
  \const@count=\z@
  \@for\next:=#2\do{\advance\const@count\@ne}%
  \expandafter\edef\csname#1\endcsname{\number\const@count}%
}
\makeatother

现在\const{Count}{\length}{\list}\const{ABC}{\FPeval}{2*3}将会起作用。

如果\FPeval是默认方法,则可以简化语法:

\documentclass{article}
\usepackage{pstricks-add,fp}

% user defined data
\def\list{1,2,3,4,5,6}

\makeatletter
\newcommand\const[3][\FPeval]{% #1=method, #2=name, #3=data
   \expandafter#1\csname#2\endcsname{#3}%
   \begingroup\edef\x{\endgroup
     \noexpand\pstVerb{/#2 \csname#2\endcsname\space def}}\x
}
\newcount\const@count
\def\length#1#2{%
  \const@count=\z@
  \@for\next:=#2\do{\advance\const@count\@ne}%
  \edef#1{\number\const@count}%
}
\makeatother

\begin{document}

\const[\length]{Count}{\list}
\Count

\const{ABC}{2*2}
\ABC
\end{document}

答案2

如果仅通过扩展进行工作,则最简单,那么 TeX 和 PS 构造的行为更相似。我稍微更改了\产品表达式中的语法,以节省解析标记的时间。

\documentclass[pstricks,border=12pt]{standalone}

\usepackage{pstricks-add,fp}

% user defined data
\def\listX{1,2,3,4,5,6}
\def\listY{1,2,3}

% to determine the number of elements in a list
\makeatletter

\long\def\length#1{%
\expandafter\xlength\expandafter0#1,\relax,}

\long\def\xlength#1#2,{%
\ifx\relax#2%
\the\numexpr#1\relax
\expandafter\@gobblefour
\fi
\expandafter\xlength\expandafter{\the\numexpr#1+1\relax}}
\makeatother

% to create constants in both TeX and PS scopes
\def\const#1#2{%
    \expandafter\edef\csname#1\endcsname{\the\numexpr#2\relax}%
    \pstVerb{/#1 \csname#1\endcsname\space def}%
}



\const{Nx}{\length{\listX}}
\const{Ny}{\length{\listY}}
\const{CellW}{1}
\const{CellH}{2}


\const{CanvasWidth}{\Nx*\CellW}
\const{CanvasHeight}{\Ny*\CellH}


\begin{document}

\begin{pspicture}[showgrid=bottom](\CanvasWidth,\CanvasHeight)
    % use other PS constants here
\end{pspicture}

\end{document}

相关内容