3

I wanted to try to learn how to define a lot of macros at one go. After I asked this on the chat room, I received some code from the awesome egreg to play with.

Here is a link to working code. There after, I tried to generalise so that, the function \definefoo can define macros whose length could be arbitrary in the sense that, there is a uniform way to define \ab, \abg, \abgd and so on...

I modified it after more discussions there.

I hope the following non-working code also serves as a pseudocode for what I am trying to achieve:

\documentclass{amsart}
\usepackage{amsmath}
\makeatletter
\def\definefoo#1#2#3#4{%
  \ifx\relax#4%
     \ifx\relax#3%
        \ifx\relax#2%
           \expandafter\def\csname#1#1\endcsname##1{%
           \csname greek#1\endcsname_{##1}}
        \fi
        \expandafter\def\csname#1#2\endscname##1##2{%
        \csname greek#1\endcsname_{##1}%
        \csname greek#2\endcsname_{##2}}
     \fi
      \expandafter\def\csname#1#2#3\endscname##1##2##3{%
      \csname greek#1\endcsname_{##1}%
      \csname greek#2\endcsname_{##2}%
      \csname greek#3\endcsname_{##3}}
  \fi
  \expandafter\def\csname#1#2#3#4\endscname##1##2##3##4{%
  \csname greek#1\endcsname_{##1}%
  \csname greek#2\endcsname_{##2}%
  \csname greek#3\endcsname_{##3}%
  \csname greek#4\endscname_{##4}}
}

\let\greeka\alpha
\let\greekb\beta
\let\greekg\gamma
\let\greekd\delta
\let\greekl\lambda
\let\greekm\mu

\definefoo a\relax\relax\relax
\definefoo ag\relax\relax\relax
\definefoo abg\relax
\definefoo abd\relax
\makeatother
\begin{document}
$\abd{ij}{kl}{mn} \aa{ij}{kl} \aa{kl}$ 
\end{document}
3
  • 2
    Could you perhaps describe in words what you try to achieve? I understand someone gave you some code that did work, you edited it, and at some point it didn't work anymore. It would be helpful to add the last bit of code that did work, and tell us what you tried from that point onward.
    – Betohaku
    Commented Apr 22, 2013 at 16:31
  • You at least need some \else branch.
    – egreg
    Commented Apr 22, 2013 at 16:39
  • @egreg Right! I am fixing it. I think the question is most likely to be closed as too localised or something like that...
    – kan
    Commented Apr 22, 2013 at 16:43

1 Answer 1

3

You need some \else branch:

\documentclass{amsart}
\usepackage{amsmath}
\def\definefoo#1#2#3#4{%
  \ifx\relax#4%
    \ifx\relax#3%
      \ifx\relax#2%
         \expandafter\def\csname#1#1\endcsname##1{%
         \csname greek#1\endcsname_{##1}}
      \else
        \expandafter\def\csname#1#2\endcsname##1##2{%
        \csname greek#1\endcsname_{##1}%
        \csname greek#2\endcsname_{##2}}
      \fi
    \else
      \expandafter\def\csname#1#2#3\endcsname##1##2##3{%
      \csname greek#1\endcsname_{##1}%
      \csname greek#2\endcsname_{##2}%
      \csname greek#3\endcsname_{##3}}
    \fi
  \else
    \expandafter\def\csname#1#2#3#4\endcsname##1##2##3##4{%
    \csname greek#1\endcsname_{##1}%
    \csname greek#2\endcsname_{##2}%
    \csname greek#3\endcsname_{##3}%
    \csname greek#4\endcsname_{##4}}
  \fi
}

\let\greeka\alpha
\let\greekb\beta
\let\greekg\gamma
\let\greekd\delta
\let\greekl\lambda
\let\greekm\mu

\definefoo a\relax\relax\relax
\definefoo ag\relax\relax
\definefoo abg\relax
\definefoo abd\relax
\makeatother

\begin{document}
$\abd{ij}{kl}{mn}$

$\ag{ij}{kl}$

$\aa{kl}$
\end{document}

I suggest you a different way.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\prop_new:N \g_kan_greek_prop
\prop_gput:Nnn \g_kan_greek_prop { a } { alpha }
\prop_gput:Nnn \g_kan_greek_prop { b } { beta }
\prop_gput:Nnn \g_kan_greek_prop { g } { gamma }
\prop_gput:Nnn \g_kan_greek_prop { d } { delta }
%% Add all the equivalences you need


\NewDocumentCommand{\definefoo}{m}
 {
  \kan_definefoo:n { #1 }
 }

\cs_new_protected:Npn \kan_definefoo:n #1
 {
  \int_case:nnn { \tl_count:n { #1 } }
   {
    {1}{ \kan_definefoo_one:n #1 }
    {2}{ \kan_definefoo_two:nn #1 }
    {3}{ \kan_definefoo_three:nnn #1 }
    {4}{ \kan_definefoo_four:nnnn #1 }
   }
   {}
 }

\cs_new_protected:Npn \kan_definefoo_one:n #1
 {
  \cs_new:cpx { S#1 } ##1
   {
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#1} } \sb { ##1 }
   }
 }
\cs_new_protected:Npn \kan_definefoo_two:nn #1 #2
 {
  \cs_new:cpx { S#1#2 } ##1 ##2
   {
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#1} } \sb { ##1 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#2} } \sb { ##2 }
   }
 }
\cs_new_protected:Npn \kan_definefoo_three:nnn #1 #2 #3
 {
  \cs_new:cpx { S#1#2#3 } ##1 ##2 ##3
   {
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#1} } \sb { ##1 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#2} } \sb { ##2 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#3} } \sb { ##3 }
   }
 }
\cs_new_protected:Npn \kan_definefoo_four:nnnn #1 #2 #3 #4
 {
  \cs_new:cpx { S#1#2#3#4 } ##1 ##2 ##3 ##4
   {
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#1} } \sb { ##1 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#2} } \sb { ##2 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#3} } \sb { ##3 }
    \exp_not:c { \prop_get:Nn \g_kan_greek_prop {#4} } \sb { ##4 }
   }
 }
\ExplSyntaxOff


\definefoo{abgd}
\definefoo{abd}
\definefoo{ab}

\begin{document}

$\Sabgd{ij}{kl}{mn}{pq}$

$\Sabd{ij}{kl}{mn}$

$\Sab{ij}{kl}$

\end{document}

Rather than doubling the letter for the "one letter case", I believe it's better to use a prefix that makes harder hitting an already defined package.


Here is another approach: you define a macro \foo that recursively eats a character from its first argument:

\documentclass{article}

\makeatletter
\def\foo#1{\foo@aux#1\@nil}
\def\foo@aux#1#2\@nil{%
  \if\relax\detokenize{#2}\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  {\do@final@foo{#1}}
  {\do@inner@foo{#1}{#2}}}
\def\do@final@foo#1#2{\csname greek#1\endcsname_{#2}}
\def\do@inner@foo#1#2#3{%
  \csname greek#1\endcsname_{#3}%
  \foo@aux#2\@nil}
\makeatother
\let\greeka\alpha
\let\greekb\beta
\let\greekg\gamma
\let\greekd\delta
\let\greekl\lambda
\let\greekm\mu

\begin{document}
$\foo{ab}{ij}{kl}$

$\foo{a}{ij}$

$\foo{aambd}{ij}{kl}{mn}{pq}{rs}$
\end{document}

enter image description here


Recommended way

Usage of macros with a variable number of arguments is not really the best approach in LaTeX, so here's a final suggestion for having a more controlled input.

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\foo}{mm}
 {
  \kan_foo:nn { #1 } { #2 }
 }
\seq_new:N \l__kan_symbols_seq
\seq_new:N \l__kan_subscripts_seq

\cs_new_protected:Npn \kan_foo:nn #1 #2
 {
  \seq_set_from_clist:Nn \l__kan_symbols_seq { #1 }
  \seq_set_from_clist:Nn \l__kan_subscripts_seq { #2 }
  \seq_mapthread_function:NNN \l__kan_symbols_seq \l__kan_subscripts_seq
   \__kan_print:nn
 }
\cs_new:Npn \__kan_print:nn #1 #2
 {
  #1\sb{#2}
 }
\ExplSyntaxOff

\begin{document}
$\foo{\alpha,\beta}{ij,kl}$

$\foo{a,\gamma,\delta}{ij,kl,mn}$
\end{document}

The macro \foo takes two lists as arguments; each element of the first list is paired to the corresponding one in the second list. Possibly more boring to type, but surely clearer.

enter image description here

1
  • Note that as of September 2014, \prop_get:Nn has been renamed to \prop_item:Nn
    – egreg
    Commented Sep 17, 2014 at 17:55

You must log in to answer this question.

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