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 – Phelype Oleinik Dec 24 '20 at 21:13
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. – Miraino Hikari Dec 28 '20 at 17:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.