Take the 2-minute tour ×
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.

Consider the following MWE:

\documentclass[12pt]{article}

\begin{document}

\def\aaa{something}
\typeout{=1==\aaa==}
\typeout{=1==\meaning\aaa==}
\typeout{}

\def\bbb{else \aaa, else}
\typeout{=2==\bbb==}
\typeout{=2==\meaning\bbb==}
\typeout{}

\def\ccc{third \bbb, level}
\typeout{=3==\ccc==}
\typeout{=3==\meaning\ccc==}
\typeout{}

\end{document}

It outputs the following to terminal:

=1==something==
=1==macro:->something==

=2==else something, else==
=2==macro:->else \aaa , else==

=3==third else something, else, level==
=3==macro:->third \bbb , level==

Thus, I'd consider (in this case) \meaning to provide unexpanded contents of a macro (that would be "null" level of expansion); while \typeout does "infinite" expansion (until no more tokens to be expanded). I've noted that \typeout calls \write:

$ texdef -t latex -c book -p titletoc typeout -f
\typeout is defined by (La)TeX.

\typeout:
macro:#1->\begingroup \set@display@protect \immediate \write \@unused {#1}\endgroup 

... so this "infinite" expansion behavior may be due to \write.

 

What I'd like, eventually, is an expandable function, which will accepts a numeric "level of expansion", and could be called like this:

# just a fake interface definition for testing
\def\expandlevel#1\nil#2\nil{
---#1---#2--
}

\edef\yyy{\expandlevel0\nil\ccc\nil}
\typeout{\yyy}

... such that:

  • When I call for level null expansion - what I get when I typeout are unexpanded contents (like \meaning); pseudo:
    * \typeout{==\expandlevel0\nil\ccc\nil==}
    ==third \bbb , level==
  • When I call for a single expansion - what I get is (pseudo):
    * \typeout{==\expandlevel1\nil\ccc\nil==}
    ==third else \aaa , else , level==
  • When I call for infinite expansion - that would be 99 levels :) - what I get is the same as \typeout would perform; pseudo:
    * \typeout{==\expandlevel99\nil\ccc\nil==}
    ==third else something, else, level==

Unexpandable/protected tokens would remain (or be shown with \inaccessible), as \typeout performs currently..

In lack of a "real" expandable macro like that, are there any tricks to coax \typeout to behave in similar fashion (if possible)?

share|improve this question

1 Answer 1

up vote 10 down vote accepted

This has nothing to do with \typeout except insofar as its argument is fully expanded because of \write, as you noted. You could ask the same of \edef, and the answer would be to use a sufficiently elaborate combination of \expandafter, \noexpand, and \unexpanded to force each token to expand the desired number of times. For example:

*\def\a{\b} \def\b{\c} \def\c{c}

*\edef\x{\noexpand \a}

*\show\x 
> \x=macro:
->\a .
<*> \show\x

? 

*\edef\x{\expandafter\noexpand \a}

*\show\x
> \x=macro:
->\b .
<*> \show\x

? 

*\edef\x{\expandafter\expandafter\expandafter\noexpand \a}

*\show\x
> \x=macro:
->\c .
<*> \show\x

? 

*\edef\x{%
  \expandafter\expandafter\expandafter\expandafter
  \expandafter\expandafter\expandafter\noexpand\x}

*\show\x
> \x=macro:
->c.
<*> \show\x

The number of \expandafters increases exponentially. The question of how to write a single expandable command that expands the desired number of times is addressed here. Note that the answer given there still only expands one token, so you can't apply it to an entire text. It is possible to play tricks with \unexpanded (a \noexpand for many tokens) and with token list registers (which, inside \edef, expand to their contents and then make the result temporarily unexpandable) to achieve similar effects.

You might be wondering, if zero expansions and infinite expansions are allowed on an entire text, why not one or more? The answer is that in fact, "infinite" expansions are done token-by-token and there is no notion of expanding the "whole text". To do zero expansions TeX simply has to dump the token list as given; the way that \meaning apparently does one expansion is that it actually changes the \catcodes of its output so that it is no longer expandable: those aren't real macros you see. You can achieve the same effect yourself if you use \scantokens in combination with a \catcode change...except that \catcode is not expandable, so you can't do that in \edef or \write. Or rather, if you do, you will just see the string "\catcode" in the result.

Anyway, if you want to expand a "whole text" a certain number of times, you could mean one of three things:

  1. Expand the first token, and then expand the first token of the result, and so on, that many times.

  2. Expand the first expandable token, then the first expandable token of the result, and so on, that many times.

  3. Expand the first expandable token; then, in the expanded text, expand everything (n - 1) times in the same way. Once you're done, move to the first "untouched" token and continue in this way to the end of the text. (Thus, expanding to a certain "depth" across the entire text.)

Rules 1 and 2 have different results:

\def\a{a}
a\a

where expanding "once" gives either "a\a" or "aa" depending on the rule. Rule 1 is relatively easy to implement using \multiexpandafter (from the other question) and \unexpanded. Rule 2 is probably impossible without embedding \expandafter and \noexpand into all your macros. Rule 3 is probably Turing-complete.

share|improve this answer
    
Fantastic, @RyanReich: "You might be wondering..." -> exactly what I was wondering; thank you for explaining it so comprehensively! Many thanks again - cheers! –  sdaau Jun 23 '12 at 18:04
1  
@sdaau: Look again, I thought of another kind of expansion to rule out :) –  Ryan Reich Jun 23 '12 at 18:51
2  
I just realized that today is Turing's 100th birthday. Therefore, I dedicate this appearance of Turing-completeness to its inventor. –  Ryan Reich Jun 23 '12 at 21:38
    
Wow, that's awesome :) I really cannot think of anything else to say but - thanks for remembering, and taking the time for the dedication, @RyanReich! Cheers! –  sdaau Jun 23 '12 at 21:42

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.