4

I have a macro lVars, defined using foreach from the pgffor package (part of PGF) as:

\newcommand{\lVars}[1]{\foreach \x [count=\ii] in {#1}{
  \ifnum\ii=1{} \else {,} \fi \lVar[\x]}
}

The intended use is in terms like \exists \lVars{a, b, c, d}, which produces the result \exists \lVar[a], \lVar[b], \lVar[c], \lVar[d]. The command \lVar[a] is another custom command of the form \newcommand{\lVar}[1][x]{\textsc{#1}}, but may become more complex shortly. I then use the newly quantified \lVar elements inside larger forumlae.

However, I'm extremely lazy. I'd quite like this macro to expose each list element as a new command of the form \lA, \lB etc, which themselves expand to the actual underlying \lVar[A], \lVar[B].... These new commands would make my formula notation significantly less verbose. These new commands should last until the next time a, b,... are used in the list parameter to the lVars macro. So, the overall usage will be situations like:

\begin{displaymath}
  \begin{array}{l}
    \exists \lVars{a, b, c}.~ \lA = \lB \implies \lA = \lC \\
    \lC = 0 \implies \lA = 0
    \exists \lVars{a, b}.~ \lA \neq \lB
  \end{array}
\end{displaymath}

And, as we see in the term $\lA = \lB$, the implication...

I've experimented with various permutations on \newcommand and \def within the body of the foreach, without any luck. Any advice or tips?

ShreevatsaR
  • 45,428
  • 10
  • 117
  • 149

1 Answers1

3
\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\lVars}{m}
 {
  % cycle through the argument
  \clist_map_inline:nn { #1 }
   {
    % print the variable
    \lVar[##1]
    % if the variable is a, define \lA
    \tl_to_uppercase:n
     {
      \cs_gset_protected:cpn { \c_wright_prefix_tl ##1 }
     }
     { \lVar[##1] }
   }
 }
% We need to store the `l' prefix in a control sequence to hide it from \uppercase
\tl_const:Nn \c_wright_prefix_tl { l }
\ExplSyntaxOff

\newcommand{\lVar}[1][x]{\textsc{#1}}

\begin{document}
\begin{displaymath}
  \begin{array}{l}
    \exists \lVars{a, b, c}.~ \lA = \lB \implies \lA = \lC \\
    \lC = 0 \implies \lA = 0
    \exists \lVars{a, b}.~ \lA \neq \lB
  \end{array}
\end{displaymath}

And, as we see in the term $\lA = \lB$, the implication...
\end{document}

However, the definition of \lC will survive forever; if you plan to use it in different cells of an array a global definition is necessary.

enter image description here


A version that accepts multiletter variables and defines \lFoo from \lVars{foo}:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\lVars}{m}
 {
  % cycle through the argument
  \clist_map_inline:nn { #1 }
   {
    % print the variable
    \lVar[##1]
    % build the name with the first letter uppercase
    \wright_make_var_name:n { ##1 }
    \cs_gset_protected:cpn { \l__wright_var_name_tl } { \lVar[##1] }
   }
 }
\tl_const:Nn \c_wright_prefix_tl { l }
\cs_new:Npn \wright_make_var_name:n #1
 {
  % get the first letter and uppercase it
  \tl_to_uppercase:n
   {
    \tl_set:Nx \l__wright_var_name_tl { \tl_head:n {#1} }
   }
  % add the rest
  \tl_put_right:Nx \l__wright_var_name_tl { \tl_tail:n {#1} }
  % add the prefix
  \tl_put_left:Nx \l__wright_var_name_tl { \c_wright_prefix_tl }
 }
\ExplSyntaxOff
\newcommand{\lVar}[1][x]{\textsc{#1}}

\begin{document}
\begin{displaymath}
  \begin{array}{l}
    \exists \lVars{a, b, c}.~ \lA = \lB \implies \lA = \lC \\
    \lC = 0 \implies \lA = 0
    \exists \lVars{a, b}.~ \lA \neq \lB
  \end{array}
\end{displaymath}

And, as we see in the term $\lA = \lB$, the implication...

Now $\forall\lVars{foo}\;\lFoo=0$
\end{document}

enter image description here

David Carlisle
  • 757,742
egreg
  • 1,121,712
  • That's lovely, thanks! Just to be a pain, is there any way to combine it with the work in http://tex.stackexchange.com/questions/7992/command-to-uppercase-the-first-letter-of-each-word-in-a-sentence to make the upper-casing only apply to the first letter of each variable? So that \lVars{a, b, foo} defines \lA, \lB and \lFoo? I think I need to learn this xparse package! – Adam Wright Apr 13 '13 at 17:14
  • 1
    @AdamWright Your wish is my command. ;-) – egreg Apr 13 '13 at 17:39
  • Thanks so much. My fingers will be eternally grateful :) – Adam Wright Apr 13 '13 at 18:12