Ser o no ser: argumentos opcionales dentro de la definición de macro

Ser o no ser: argumentos opcionales dentro de la definición de macro

La parte de la versión A en el siguiente ejemplo se define header/footermediante macros del paquete fancyhdr.

Aunque esta versión es viable, es un logro incómodo porque la misma parte del código ( \ifnum...) se escribe dos veces.

Excepto el argumento opcional n.º 2, todo el resto del código es exactamente igual. Para mejorarlo, probé la versión B a continuación, pero no funciona en absoluto.

Será terrible, especialmente cuando la misma parte del código sea grande.

Entonces, para resumir, ¿existe una mejor manera de manejar argumentos opcionales (estar allí o no) para evitar código duplicado pesado?

\documentclass{article}
\usepackage{geometry,fancyhdr,xparse}
\geometry{showframe}

\begin{document}
first page\par\vspace{80em} second page
\pagestyle{fancy}
\fancyhf{}

%Version A: workable %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentCommand{\firstpage}{momm}{%
  \IfNoValueTF{#2}
  {#1{%
      \ifnum\value{page}=1
      #3% content of header/footer only at the first page
      \else
      #4% content of header/footer at the rest pages
      \fi
    }
  }
  {#1[#2]% the only diferrence between the two branches of \IfNoValueTF is, whether introducing the optional argument #2
    {%
      \ifnum\value{page}=1
      #3% content of header/footer only at the first page
      \else
      #4% content of header/footer at the rest pages
      \fi
    }
  }
}%\firstpage

% Test
\firstpage{\fancyhead}[c]{only at the first page}{at rest pages}
\firstpage{\rhead}{r first}{r rest}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Version B: not workable %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\NewDocumentCommand{\firstpageA}{momm}{%
   #1 \IfNoValueTF{#2}{}{[#2]}
      \ifnum\value{page}=1
      #3% content of header/footer only at the first page
      \else
      #4% content of header/footer at the rest pages
      \fi
}%\firstpageA

% Test
\firstpageA{\fancyhead}[c]{only at the first page}{at rest pages}
\firstpageA{\rhead}{r first}{r rest}  

\end{document}

ingrese la descripción de la imagen aquí

Respuesta1

Creo que no es útil intentar encajar una sintaxis incómoda en un comando como ese.

Es más gratificante dedicar un poco más de tiempo a idear una sintaxis más amigable. aqui te propongo

\sethf{
  head = <contents of all headers, except possibly the first>,
  foot = <contents of all footers, except possibly the first>,
  pos = <l|c|r>,
  first = <possible exception for first header/footer>,
}

Solo se debe utilizar uno entre heado en una llamada de .foot\sethf

\documentclass{article}
\usepackage{fancyhdr,xparse}

\usepackage[paper=a6paper]{geometry} % smaller pictures
\usepackage{lipsum} % mock text

\pagestyle{fancy}
\fancyhf{}

\ExplSyntaxOn
\NewDocumentCommand{\sethf}{m}
 {
  \tl_clear:N \l__lyl_hf_pos_tl
  \tl_clear:N \l__lyl_hf_first_tl
  \tl_clear:N \l__lyl_hf_headfoot_tl
  \keys_set:nn { lyl/hf } { #1 }
  \lyl_hf_set:
 }

\keys_define:nn { lyl/hf }
 {
  head  .code:n   = \__lyl_hf_aux:Nn \fancyhead { #1 },
  foot  .code:n   = \__lyl_hf_aux:Nn \fancyfoot { #1 },
  pos   .tl_set:N = \l__lyl_hf_pos_tl,
  first .tl_set:N = \l__lyl_hf_first_tl,
 }

\tl_new:N \l__lyl_hf_headfoot_tl

\cs_new_protected:Nn \__lyl_hf_aux:Nn
 {
  \cs_set_eq:NN \__lyl_hf_temp:w #1
  \tl_set:Nn \l__lyl_hf_headfoot_tl { #2 }
 }

\cs_new_protected:Nn \lyl_hf_set:
 {
  \tl_if_empty:NT \l__lyl_hf_first_tl
   {
    \tl_set_eq:NN \l__lyl_hf_first_tl \l__lyl_hf_headfoot_tl
   }
  \__lyl_hf_set:NVVV 
   \__lyl_hf_temp:w        % \fancyhead or \fancyfoot
   \l__lyl_hf_pos_tl       % position
   \l__lyl_hf_first_tl     % first page
   \l__lyl_hf_headfoot_tl  % other pages
 }
\cs_new_protected:Nn \__lyl_hf_set:Nnnn
 {
  #1 [ #2 ] { \int_compare:nTF { \value{page} = 1 } { #3 } { #4 } }
 }
\cs_generate_variant:Nn \__lyl_hf_set:Nnnn { NVVV }
\ExplSyntaxOff

\sethf{
  head = other pages,
  first = first page,
  pos = c,
}

\sethf{pos = r, foot=\thepage}

\begin{document}

\lipsum[1-2]

\end{document}

ingrese la descripción de la imagen aquí

Para responder a su pregunta: use una macro para el código duplicado.

\documentclass{article}
\usepackage{fancyhdr,xparse}

\usepackage[paper=a6paper]{geometry} % smaller pictures
\usepackage{lipsum} % mock text

\pagestyle{fancy}
\fancyhf{}

\NewDocumentCommand{\firstpage}{momm}{%
  \IfNoValueTF{#2}
   {\setfirstpage{#1}{#3}{#4}}
   {\setfirstpage{#1[#2]}{#3}{#4}}%
}
\NewDocumentCommand{\setfirstpage}{mmm}
 {
  #1{\ifnum\value{page}=1 #2\else #3\fi}
 }

\firstpage{\fancyhead}[c]{first page}{other pages}
% can also be \firstpage{\chead}{first page}{other pages}

\begin{document}

\lipsum[1-2]

\end{document}

podríareemplace la definición aquí con

\ExplSyntaxOn

\NewDocumentCommand{\firstpage}{momm}
 {
  \exp_last_unbraced:Nf #1 \IfNoValueTF{#2}{}{[#2]}
   {
    \int_compare:nTF { \value{page}=1 } { #3 } { #4 } 
   }
 }

\ExplSyntaxOff

pero no es algo que haría yo mismo. El código \IfNoValueTF{#2}{}{[#2]}se puede reemplazar de manera más sencilla con \IfValueT{#2}{[#2]}.

Respuesta2

Para el ejemplo específico, \thispagestyleprobablemente sería mejor simplemente usarlo en la primera página, pero para la pregunta general, puede evitar el escaneo previo de los argumentos hasta después de las pruebas de argumentos opcionales, y una macro auxiliar puede evitar la duplicación de código:

\documentclass{article}
\usepackage{geometry,fancyhdr,xparse}
\geometry{showframe}

\begin{document}
first page\par\vspace{80em} second page
\pagestyle{fancy}
\fancyhf{}


\def\fpageTF#1#2#3{#1{\ifnum\value{page}=1 #2\else #3\fi}}



\NewDocumentCommand{\firstpage}{mo}{%
  \IfNoValueTF{#2}{\fpageTF{#1}}{\fpageTF{#1[#2]}}}


% Test
\firstpage{\fancyhead}[c]{only at the first page}{at rest pages}
\firstpage{\rhead}{r first}{r rest}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\end{document}

información relacionada