1

I have a function that do create functions on the fly, but I cannot figure how to make the created function to have parameters.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%       CHARACTER MAKER
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\ExplSyntaxOn

% Define Special
\tl_new:N  \l_character_firstname_tl
\tl_new:N  \l_character_lastname_tl
\tl_new:N  \l_character_title_tl

\int_new:N \l_character_age_int


\keys_define:nn { Character/Identity } {
      firstname .tl_set:N = \l_character_firstname_tl
    , lastname .tl_set:N = \l_character_lastname_tl
    , title    .tl_set:N = \l_character_title_tl
    , age      .int_set:N = \l_character_age_int
    , unknown  .code:n = {}
}

% #1 * si féminin
% #2 - si élision voyelle / h
% #3 [options] - lastname, title, age
% #4 < simpleVarName > (par défaut, prénom)
% #5 { prénom }
% il va créer seule les autres versions
\NewDocumentCommand{\createCharacter}{s t- o D<>{#5} m}{
    
    % we don't want that the unset keys are carried over from the previous ones
    \group_begin:
    \IfValueT{#3}{\keys_set:nn{Character/Identity}{#3}}
    
    \cs_new_protected:cpx { #4 Age } { \exp_not:V \l_character_age_int }
    \cs_new_protected:cpx { #4 AgeAlpha } { \numberstringnum{ \exp_not:V \l_character_age_int } }
    \cs_new_protected:cpx { #4 AgeOrd } { \ordinalnum{ \exp_not:V \l_character_age_int } }
    
    \cs_new_protected:cpx { #4 AgeDiff }:nn ##1 {\fp_eval:n { \exp_not:V \l_character_age_int - ##1 }}
    \cs_new_protected:cpx { #4 AgeDiffAlpha }:nn ##1 { \numberstringnum{ \fp_eval:n { \exp_not:V \l_character_age_int - ##1 } } }
    \cs_new_protected:cpx { #4 AgeDiffOrd }:nn ##1 { \ordinalnum{ \fp_eval:n { \exp_not:V \l_character_age_int - ##1 } } }
        
    \cs_new_protected:cpn { #4 Name }  { #5 }
    \cs_new_protected:cpx { #4 FName }  { \use:c { #4 Name } ~ \exp_not:V \l_character_lastname_tl }
    \cs_new_protected:cpx { #4 LName }  { \exp_not:V \l_character_lastname_tl }
    \cs_new_protected:cpx { #4 Title }  { \exp_not:V \l_character_title_tl }
    \cs_new_protected:cpn { #4 Formal } { \use:c { #4 Title } \nobreakspace \use:c { #4 LName } }
    \cs_new_protected:cpx { #4 HW }  { \exp_not:V \l_character_handwritting_tl }
    
\group_end:

\ExplSyntaxOff

By themselves, Age, AgeAlpha, and AgeOrd works perfectly, but the AgeDiff family don't.

Let's say I'm creating a new characters using this:

\createCharacter[lastname=Smith, age=39]<hero>{John}
\createCharacter*[lastname=Wilson, age=37]<wife>{Jane}

And that further in my text I'm using writing this:

\heroName, a man of \heroAgeAlpha\ years old, is married to a nice woman, \wifeName, who is \heroAgeDiffAlpha{\wifeAge}\ younger than him. He engaged with her when he was \heroAgeDiff{3}.

I will receive errors for \heroAgeDiffAlpha and \heroAgeDiff.

How can I make it works?

1
  • 1
    In \cs_new_protected:cpx { #4 AgeDiff }:nn the :nn should be inside the braces, so \cs_new_protected:cpx { #4 AgeDiff:nn }, otherwise the :nn string itself will be a parameter to \#4AgeDiff. Or remove the :nn, since it's a document-level command Dec 24, 2020 at 21:13

1 Answer 1

2

You’re defining user level commands, so they should have no signature. On the other hand, the signature :nn would be wrong anyway, because they take just one argument.

I’d use \int_eval:n, rather than \fp_eval:n, because the user should only use integers in that context. There’s another flaw; I’ll use the AgeDiff example, where you want

\cs_new_protected:cpx { #4 AgeDiff } ##1
  {
   \exp_not:N \int_eval:n { \int_use:N \l_character_age_int - ##1 }
  }

because you can’t evaluate the difference at definition time. With this definition if I do \show\heroAgeDiff I get the expected

> \heroAgeDiff=\protected\long macro:
#1->\int_eval:n {39-#1}.

Here's the complete fix:

\documentclass{article}
\usepackage{fmtcount}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%       CHARACTER MAKER
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\ExplSyntaxOn

% Define Special
\tl_new:N  \l_character_firstname_tl
\tl_new:N  \l_character_lastname_tl
\tl_new:N  \l_character_title_tl

\int_new:N \l_character_age_int


\keys_define:nn { Character/Identity } {
      firstname .tl_set:N = \l_character_firstname_tl
    , lastname .tl_set:N = \l_character_lastname_tl
    , title    .tl_set:N = \l_character_title_tl
    , age      .int_set:N = \l_character_age_int
    , unknown  .code:n = {}
}

% #1 * si féminin
% #2 - si élision voyelle / h
% #3 [options] - lastname, title, age
% #4 < simpleVarName > (par défaut, prénom)
% #5 { prénom }
% il va créer seule les autres versions
\NewDocumentCommand{\createCharacter}{s t- o D<>{#5} m}{
    
    % we don't want that the unset keys are carried over from the previous ones
    \group_begin:
    \IfValueT{#3}{\keys_set:nn{Character/Identity}{#3}}
    
    \cs_new_protected:cpx { #4 Age } { \int_eval:n { \l_character_age_int } }
    \cs_new_protected:cpx { #4 AgeAlpha }
      {
       \numberstringnum { \int_eval:n { \l_character_age_int } }
      }
    \cs_new_protected:cpx { #4 AgeOrd }
      {
       \ordinalnum { \int_eval:n { \l_character_age_int } }
      }

    \cs_new_protected:cpx { #4 AgeDiff } ##1
      {
       \exp_not:N \int_eval:n { \int_use:N \l_character_age_int - ##1 }
      }
    \cs_new_protected:cpx { #4 AgeDiffAlpha } ##1
      {
       \numberstringnum { \exp_not:N \int_eval:n { \int_use:N \l_character_age_int - ##1 } }
      }
    \cs_new_protected:cpx { #4 AgeDiffOrd } ##1
      {
       \ordinalnum { \exp_not:N \int_eval:n { \int_use:N \l_character_age_int - ##1 } }
      }

    \cs_new_protected:cpn { #4 Name }  { #5 }
    \cs_new_protected:cpx { #4 FName }  { \exp_not:c { #4 Name } ~ \exp_not:V \l_character_lastname_tl }
    \cs_new_protected:cpx { #4 LName }  { \exp_not:V \l_character_lastname_tl }
    \cs_new_protected:cpx { #4 Title }  { \exp_not:V \l_character_title_tl }
    \cs_new_protected:cpx { #4 Formal } { \exp_not:c { #4 Title } \exp_not:N \nobreakspace \exp_not:c { #4 LName } }
%    \cs_new_protected:cpx { #4 HW }  { \exp_not:V \l_character_handwritting_tl }
    
    \group_end:
}

\ExplSyntaxOff

\createCharacter[lastname=Smith, age=39]<hero>{John}
\createCharacter*[lastname=Wilson, age=37]<wife>{Jane}

\begin{document}

\heroName, a man of \heroAgeAlpha\ years old, is married to a nice woman, 
\wifeName, who is \heroAgeDiffAlpha{\wifeAge}\ younger than him. 
He engaged with her when he was \heroAgeDiff{3}.

\end{document}
1
  • That works magnificently. Thanks a lot. Dec 28, 2020 at 17:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .