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 Mar 30 at 14:23
    
I corrected that before to see your comment sorry ^^" some mistakes after first question submission. – galex-713 Mar 30 at 14:45
    
I also updated the title (the error was not this one finally) – galex-713 Mar 30 at 14:55
up vote 9 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 Mar 30 at 14:56
    
Yes I just noticed what you said on rebracing #2 and I deleted my comment and accepted your answer. – galex-713 Mar 30 at 15:00
    
@galex-713 I saw the tick flash to wipet and back:-) oh no, and back again:( – David Carlisle Mar 30 at 15:01
    
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 Mar 30 at 15:03
    
@galex-713 I'll probably to survive without your 15 points:-) – David Carlisle Mar 30 at 15:26

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:

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

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

The \@tfor function is essentially the abstract version of the \slowRomannumeral trick in your variant: it consumes one item at a time from the token list passed between := and \do, doing \def\next{<item>} (\next can be any token). The main difference is exactly this: we need to expand \next if we don't want that it is incorporated in the definition of \N and so on. Therefore the long chain of \expandafter's is needed. An item in this context is a single token or a braced group.

The \tl_map_inline:nn method is much better, because the current item is available “literally” as #1 (so in the body of a definition it must be called ##1).

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 Mar 30 at 20:52
1  
@galex-713 It is used in several packages. – egreg Mar 30 at 20:59
    
8 hours ago when I answered I nearly put a comment starting a countdown to a map_inline answer from you:-) – David Carlisle Mar 30 at 22:46
    
Oh that’s interesting! I didn’t know about @tfor yet ^^" (I’ll be reading its source to try to understand it soon ^^), but well, I didn’t end your book yet ^^ but why all those \expandafter near the end of the line? (how can work the third-last and last while there’s no “second token” after it except the closing brace? and I’m working on how to make the \mathbb optionnal if no optional argument is given – galex-713 Apr 1 at 8:48
1  
@galex-713 The following token, not group. So \expandafter{\next} expands \next before the { has its effect. – egreg Apr 2 at 14:38

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
1  
you mean xinttools isn't an over-used package ?!?! that's shocking ! egreg himself says having the item "literally as #1" was (quote) much better ;-) Have you looked at TeX by Topic? – jfbu Apr 1 at 9:12
1  
I didn’t know about it sorry (is it used in a lot of packages too so?), I just learned about xparse not so long ago… and I think I’ve understood xparse is more used/more general than xinttools… Yet I like to being able to understand how does works what I’m using so I’m planning to study xparse before, and if you think it’s worth maybe xinttools too. (Oh and I just noticed about \@namedef! Interesting too! is there some version of it with \newcommand/\*newcommand?). Btw, what’s TeX by Topic? – galex-713 Apr 1 at 9:55
1  
@galex-713 I was just making a little joke, as xinttools is my own package ;-) naturally great package xparse is much more used, in relation to the whole of expl3, programming layer of future LaTeX3. In contrast xinttools provides some random utilities à la Plain TeX, which were useful for me in other contexts. TeX by Topic is a well-known reference book for people who want to master TeX language; complementary to TeXBook. Reading it is good way to master the basics, so that you then understand what LaTeX3 is built upon, even if ultimately it will hide all of those roots. – jfbu Apr 1 at 10:01
1  
@galex-713 I suspect one shouldn't say 'LaTeX3 is going to build on xparse', but from what I gather, presumably much of the syntax of xparse for the end-user will indeed be part of what LaTeX3 will offer. Please people correct me here if needed. (it is actually xparse which is built upon future LaTeX3 in a way) – jfbu Apr 1 at 10:14
1  
@galex-713 the xparse syntax looks indeed different with the rest of legacy LaTeX, but it has strong justifications. Obviously, xparse is very powerful package and I think its facilities will be part of how LaTeX3 will do things for the end users. It greatly facilitates things for package authors as well who won't have to re-invent the wheel each time. – jfbu Apr 1 at 10:18

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.