1

Let suppose you have a recursive TeX macro \formula (with inner control sequences advancing local counters), which once expanded and typsetted outputs an expression that meets all your needs: for instance an expression like f(x) (in a dvi output).

How to get this typesetted formula back as a return string of characters that you can use as a replacement "verbatim" text of another macro, such as \def\secondformula{f(x)}?

Here is as a MWE a definition of formula defining through recursion a Bessel function of the first kind of any order

\newcount\BesselOrder
\newcount\BesselOrderMinusOne

\def\BesselZERO{besj0(x)}
\def\BesselONE{besj1(x)}

\def\Recursion{%
\advance\BesselOrder by -1
\advance\BesselOrderMinusOne by -1
((2 * \the\BesselOrder / x) * {\BesselJ{\the\BesselOrder}} - \BesselJ{\the\BesselOrderMinusOne}) 
}

\def\BesselJ#1{%
    \BesselOrder=#1%
    \BesselOrderMinusOne = \BesselOrder%
    \advance\BesselOrderMinusOne by -1%
    \ifnum\BesselOrder = 0
        \let\next=\BesselZERO
    \fi
    \ifnum\BesselOrder = 1
        \let\next = \BesselONE
    \fi
    \ifnum\BesselOrder > 1 
        \let\next = \Recursion
    \fi
    \next
}
  • 3
    \edef\secondformula{\formula} might work if \formula is completely expandable. If it is only expandable to some degree, finer \expandafter precision might help. But if your \formula performs assignments you are usually out of luck since it won't be expandable. I'm sure I'm missing something here. Would it be possible to come up with a toy example that shows what you are trying to do (an MWE: tex.meta.stackexchange.com/q/228/35864)? – moewe Mar 18 at 10:05
  • If this is only about the typeset output it might help to store the result in a box and reuse the box. \newsavebox{\formulabox}\savebox{\formulabox}{\formula}\usebox{\formulabox} Note that the code is executed once at the \savebox instruction and then 'frozen', i.e. every \usebox afterwards will result in the same output and no side-effects (until the box is overwritten with \savebox). – moewe Mar 18 at 10:14
  • @moewe thank you for your useful comments. I want to expand the expression of bessel functions of order n>0 through recursion. \formula is doing the work correctly but with assignments so it is not fully expandable as far as I understand your first answer. I edit the post and show you as a MWE the \formula definition. – Pete Mar 18 at 10:21
  • Ooops, sorry. I just added in the missing counter definitions almost at the same time when you edited the question, that made your modifications undone. – moewe Mar 18 at 10:32
  • As far as I can see this definition is indeed not expandable. I'm also not sure if the boxes can help you here, since they usually are not context sensitive enough to allow for nice lines breaking and so are not suitable for longer contents. Another way would be to have \BesselJ assign the 'output' to a macro. It wouldn't be expandable itself, but you could re-use the output macro. I couldn't see an easy way to do that for this use case, though. – moewe Mar 18 at 10:36
1
% This is to be compiled with e-TeX. (Not TeX and also not LaTeX.)

\overfullrule=0pt
\parindent=0ex
\parskip=\baselineskip
\begingroup\catcode`\%=12 \lowercase{\endgroup\def\percentchar{%}}%

% Pete's bessel-routine:
% ======================

\newcount\BesselOrder
\newcount\BesselOrderMinusOne

\def\BesselZERO{besj0(x)}
\def\BesselONE{besj1(x)}

\def\Recursion{%
\advance\BesselOrder by -1
\advance\BesselOrderMinusOne by -1
((2 * \the\BesselOrder/ x) * {\BesselJ{\the\BesselOrder}} - \BesselJ{\the\BesselOrderMinusOne})
}

\def\BesselJ#1{%
    \BesselOrder=#1%
    \BesselOrderMinusOne = \BesselOrder%
    \advance\BesselOrderMinusOne by -1%
    \ifnum\BesselOrder = 0
        \let\next=\BesselZERO
    \fi
    \ifnum\BesselOrder = 1
        \let\next = \BesselONE
    \fi
    \ifnum\BesselOrder > 1 
        \let\next = \Recursion
    \fi
    \next
}

% Ulrich's bessel-routine:
% ========================
%
% The routine doesn't need temporary assignments and the like and is based
% on expansion only.
% 
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
% !!!! Due to the \numexpr-thingie e-TeX-extensions are required. !!!!
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
%
% The routine as a trick for triggering expansion uses \romannumeral-expansion:
% When due to \romannumeral (La)TeX does gather together a sequence of digits
% trailed by a space as the number which it has to convert, expandable tokens
% get expanded.
% When in the end a number is gathered together which is not positive, as the result
% of the conversion (La)TeX will not deliver any token at all.
% Thus one can nicely (ab)use \romannumeral for triggering a lot of
% expansion-work and flipping-arguments-around-work as long as one ensures
% that in the end \romannumeral will not find a positive number.
%
% Due to \romannumeral-expansion \UDBesselJ will deliver the result in
% two expansion-steps/after "being hit" by two \expandafter .
%
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
% !!! \UDBesselJ will take its toll at the semantic nest and at the input-stack. !!!
% !!!                                                                            !!!
% !!! Don't use it with all too large values in the argument.                    !!!
% !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

\long\def\exchange#1#2{#2#1}%
\long\def\passfirsttosecond#1#2{#2{#1}}%
\long\def\firstoftwo#1#2{#1}%
\long\def\secondoftwo#1#2{#2}%
\def\romannumeralstop{ }%

\def\UDBesselJ#1{%
  \romannumeral0%
  \ifnum#1 = 0 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
  {\romannumeralstop besj0(x)}{%
    \ifnum#1 = 1 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
    {\romannumeralstop besj1(x)}{%
      \ifnum#1 > 1 \expandafter\firstoftwo\else\expandafter\secondoftwo\fi
      {%
        \expandafter\exchange\expandafter{%
          \romannumeral0%
          \exchange{ }{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter}%
          \expandafter\UDBesselJ\expandafter{\the\numexpr#1-2\relax}) %
        }{%
          \expandafter\passfirsttosecond\expandafter{%
            \romannumeral0%
            \exchange{ }{\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter}%
            \expandafter\UDBesselJ\expandafter{\the\numexpr#1-1\relax}%
          }%
          {\expandafter\exchange\expandafter{\the\numexpr#1-1\relax}{\romannumeralstop((2 * }/ x) * } - %
        }%
      }{\romannumeralstop}%
    }%   
  }%
}%

% Testing the routines:
% =====================

{\tt\string\BesselJ\string{4\string}} yields:\hfil\break
\BesselJ{4}

\hbox to\hsize{\null\hrulefill\null}\nointerlineskip

{\tt\string\UDBesselJ\string{4\string}} yields:\hfil\break
\UDBesselJ{4}

\hbox to\hsize{\null\hrulefill\null}\nointerlineskip

{\tt\string\expandafter\string\expandafter\string\expandafter\string\def\hfil\break
\string\expandafter\string\expandafter\string\expandafter\string\secondformula\hfil\break
\string\expandafter\string\expandafter\string\expandafter\string{\percentchar\hfil\break
\string\UDBesselJ\string{4\string}\string}}

yields the macro
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\secondformula
\expandafter\expandafter\expandafter{%
\UDBesselJ{4}}%
{\tt\string\secondformula:}

{\tt\meaning\secondformula}

\hbox to\hsize{\null\hrulefill\null}\nointerlineskip

{\tt\string\secondformula} yields:\hfil\break
\secondformula

\bye

enter image description here

  • @ Ulrich: Congratulations ! I have compiled your new definitions with pdfTeX flawlessly. Your mastering of the \romanumeral expansion process is really impressive to my unexperienced TeXnician eyes. – Pete Mar 18 at 21:50
  • I need \second formula for both usage. But as long as \secondformula is an expanded formula that can be correctly lexically analyzed by the gnuplot software or by pgf+gnuplot tools everything should be ok. So in this respect I would keep * as the multiplication sign and for the extra space near the closing parenthesis, this is not essential. Thanks a lot Ulrich for your wonderful routine. – Pete Mar 18 at 22:27

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.