TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I’m a fan of factorization and hate code repetition. So I was trying to define a macro which defines for me all the common mathematical sets commands (\C, \N, etc.) and made a recursive function inspiring of \slowRomannumeral p. 24 from these TeX and LaTeX programmation notes.

So I did this first:

\def\defsets#1{\defnextset #1@}
\def\defnextset#1{\ifx @#1 \else
    \expandafter\newcommand\csname #1\endcsname{\mathbb{#1}}
    \expandafter\defnextset
  \fi}
\defsets{RDNZQC}

But I soon realised that I needed something alike for my math operators, exactly the same but just with \DeclareMathOperator instead of \newcommand and without \mathbb, so I defined a \defset command and tried to make my main macro high-order:

\newcommand{\defset}[1]{\expandafter\newcommand\csname #1\endcsname{\mathbb{#1}}}
\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2 \else
    #1#2\relax
    \expandafter\defnext#1
  \fi}
\defsets{RDNZQC}

And I checked a lot of things: I put a \relax otherwise for an unkown reason it tries to redefine expandafter, the first \newcommand does work, #1#2 should work, and using \def instead of \newcommand* to define \defset I get the following error:

ERROR: Missing \endcsname inserted.

--- TeX said ---
<to be read again> 
                   \let 
l.68 \defsets{RDNZQC}

and adding an \expandafter makes the same as the actual current code with \newcommand* (and all the same combinations with it): an infinite loop.

So how to make this code work? so I can just make a \defop and do the same thing for my math operators and some code tricks with each operator command between braces (since this currently works for single characters actually).

share|improve this question
    
in your second fragment did you mean \defnextset to be \defnext (which is used but not defined) – David Carlisle 18 hours ago
    
I corrected that before to see your comment sorry ^^" some mistakes after first question submission. – galex-713 17 hours ago
    
I also updated the title (the error was not this one finally) – galex-713 17 hours ago
up vote 5 down vote accepted

You cannot skip more than one token by one \expandafter. There are more solutions of your problem. For example, you can set the used def-method by \let first:

\def\defset#1{\expandafter\def\csname#1\endcsname{\mathbb{#1}}}

\def\defsets#1{\let\defnextA=\defset \defnext #1@}
\def\defnext#1{\ifx @#1\else
    \defnextA{#1}%
    \expandafter\defnext
  \fi}

\defsets{RDNZQC}

Second: you can repeat the def-method as #1 but with one more \expandafter:

\def\defset#1{\expandafter\def\csname#1\endcsname{\mathbb{#1}}}

\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2\else
    #1{#2}%
    \expandafter\defnext\expandafter#1%
  \fi}

\defsets{RDNZQC}
share|improve this answer

You need to expand away the \fi

\RequirePackage{amsmath}

\makeatletter

\newcommand{\defset}[1]{\expandafter\newcommand\csname #1\endcsname{\mathbb{#1}}}
\def\defsets#1{\defnext\defset #1@}
\def\defnext#1#2{\ifx @#2%
    \expandafter\@gobble
   \else
    #1{#2}%
    \expandafter\@firstofone
   \fi    
    {\defnext#1}}
\defsets{RDNZQ{Zzz}C}


\show\Z
\show\Zzz


\newcommand*{\defop}[1]{\expandafter\DeclareMathOperator\csname #1\endcsname{#1}}

\defnext\defop {Vect}{Spec}@

{\let\protect\show\Vect}

\stop

Produces

LaTeX2e <2016/03/31>
Babel <3.9q> and hyphenation patterns for 81 language(s) loaded.
> \Z=\long macro:
->\mathbb {Z}.
l.15 \show\Z

? 
> \Zzz=\long macro:
->\mathbb {Zzz}.
l.16 \show\Zzz

? 
> \Vect =\long macro:
->\qopname \newmcodes@ o{Vect}.
\Vect ->\protect \Vect  

l.23 {\let\protect\show\Vect
                            }
? 

Note you need to re-brace #2 as {#2} to support multiple token arguments.

share|improve this answer
    
@galex-713 works for me, I updated with your mathoperator example. – David Carlisle 17 hours ago
    
Yes I just noticed what you said on rebracing #2 and I deleted my comment and accepted your answer. – galex-713 17 hours ago
    
@galex-713 I saw the tick flash to wipet and back:-) oh no, and back again:( – David Carlisle 17 hours ago
    
Well I was going to ask him to add some of your changes like the \show and above all the rebracing of #2 before then noticed he did integrate them without highlighting them. – galex-713 17 hours ago
    
@galex-713 I'll probably to survive without your 15 points:-) – David Carlisle 17 hours ago

Seems I wake up after the battle, all dust has settled ...

\documentclass{article}
\usepackage{amsmath}
\usepackage{xinttools}


\makeatletter
\newcommand\defsets [1]
   {\xintFor* ##1 in {#1} \do {\@namedef{##1}{\mathbb{##1}}}}
\makeatother

\newcommand\defops [1]
   {\xintFor ##1 in {#1} \do {\expandafter
           \DeclareMathOperator\csname ##1\endcsname{##1}}}


\defsets{RDNZQC}
\defops{Vect, Spec}

\begin{document}

\texttt{\meaning\R}

\texttt{\meaning\Q}

\texttt{\meaning\Spec}

\texttt{\expandafter\meaning\csname Spec \endcsname}

\end{document}

enter image description here

share|improve this answer

The problem is of course in \expandafter\defnext#1 that tries to expand whatever is replaced for #1 instead of the intended \fi.

If you hate code repetition, you'll surely like this, where \defsets and \defops are basically one-liners.

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

\ExplSyntaxOn
\NewDocumentCommand{\defsets}{m}
 {
  \tl_map_inline:nn { #1 }
   {
    \cs_new_protected:cpn { ##1 } { \mathbb{##1} }
   }
 }
\NewDocumentCommand{\defops}{m}
 {
  \clist_map_inline:nn { #1 } 
   {
    \galex_declaremathoperator:cn { ##1 } { ##1 }
   }
 }
\cs_set_eq:NN \galex_declaremathoperator:Nn \DeclareMathOperator
\cs_generate_variant:Nn \galex_declaremathoperator:Nn { c }
\ExplSyntaxOff

\defsets{RDNZQC}
\defops{Vect,Spec}

\begin{document}

\texttt{\meaning\R}

\texttt{\meaning\Q}

\texttt{\meaning\Spec}

\texttt{\expandafter\meaning\csname Spec \endcsname}

\end{document}

Only one \expandafter to show that \Spec does the right thing. None in the coding part.

I could have used

\exp_args:Nc \DeclareMathOperator { ##1 } { ##1 }

instead of defining \galex_declaremathoperator:Nn and a variant thereof. But this way all is cleaner and in line with recommendations.

enter image description here

The same is obtained with \@tfor:

\documentclass{article}
\usepackage{amsmath}

\makeatletter
%\let\@xp\expandafter % already done by amsmath
\newcommand{\defsets}[2][\newcommand]{%
  \@tfor\next:=#2\do{%
    \@xp#1\csname\next\@xp\endcsname\@xp{\@xp\mathbb\@xp{\next}}%
  }%
}
\makeatother

\defsets{RDNZQC}
\defsets[\DeclareMathOperator]{{Vect}{Spec}}
share|improve this answer
    
Omg I really need to learn to use this xparse and to become used of it… each time I see it it seems to me so verbose! kinda like Java… That seems a whole language on the top of TeX! is that already used in some packages? or internally within LaTeX? – galex-713 11 hours ago
1  
@galex-713 It is used in several packages. – egreg 11 hours ago
    
8 hours ago when I answered I nearly put a comment starting a countdown to a map_inline answer from you:-) – David Carlisle 9 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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