5

I'm currently messing around with macros (rather new) and I seem to be missing something rather basic about LaTeX/TeX macros:

\def\car{Yes}
    \def\iszero#1{
    \ifnum#1=0{
        \let \car = Yes
    }
    \else{
        \let \car = No
    }
    \car
}
\iszero{1}

Returns Yes.

I was wondering why this happens and how I can prevent LaTeX from prematurely replacing \car with it's current value.

2
  • 2
    (1) You have a \fi missing (look at the output from when you run tex). (2) If you're using solely LaTeX (and not plain TeX), they say not to use \def (3) You can use \tracingmacros=1 and look in the log file, to see what's going on (4) You can also use \message or \show I guess. (5) Also \tracingassigns=1 which comes from eTeX (6) Something like \let\car=No will only eat up the N and leave o to appear in the output. (7) Assignments are reset when you exit the group. You can use \global\let to override this. (8) I'm not an expert so someone else will answer hopefully :-) May 1 '17 at 4:42
  • \let\car = No will 'define' car to correspond to the single character token 'N' and leaves 'o' in the input stream, being displayed then (assuming application of \ifzero in LaTeX's document body). You can't assign a bunch of tokens with let unless it is a control sequence token
    – user31729
    May 1 '17 at 5:38
7

You want

\def\car{Yes}
\def\iszero#1{%
  \ifnum#1=0 % Terminate number with a space
    \def\car{Yes}%
  \else
    \def\car{No}%
  \fi
}
\iszero{1}

You are using a TeX primitive conditional, so the two branches are not places in braces: instead the are delimited by the end of the conditional, the \else and the \fi. The \let primitive can only be used to assigned one token to the value of a second one: you can't use it to define a macro, which needs \def.

2
  • The final \car is missing in the above (so the above prints nothing). Also, perhaps the OP was thinking of something like the following: one could also have \def\yes{Yes} and \def\no{No}, and then inside the \if use \let\car=\yes or \let\car=\no respectively. May 1 '17 at 7:32
  • @ShreevatsaR I considered \yes and \no but without the wider context it's hard to be sure what is best; much the same with the find \car, which I suspect may be for diagnostics (otherwise why no just print the text in the conditional).
    – Joseph Wright
    May 1 '17 at 7:34
3

The syntax for TeX conditionals does not use braces for the true and false branches.

Also \let behaves differently from what you seem to think: \let\foo=<token> makes \foo (almost) equivalent to <token>. In the case of

\let\car = Yes

the token Y would be assigned to \car and es would be printed (if in the nonskipped branch); same for \let\car = No.

You should use \def, instead. But there are better ways that don't require having \car.

Assuming plain TeX,

\long\def\firstoftwo#1#2{#1}
\long\def\secondoftwo#1#2{#2}

\def\iszero#1{%
  \ifnum#1=0
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
  {Yes}{No}%
}

would work: the \expandafter trick sweeps away the remnants of the conditional text, leaving either \firstoftwo{Yes}{No} or \secondoftwo{Yes}{No} in the input stream.

This can be generalized

\def\IfIsZeroTF#1{%
  \ifnum#1=0
    \expandafter\firstoftwo
  \else
    \expandafter\secondoftwo
  \fi
}

to be called like

\IfIsZeroTF{1}{Yes}{No}
2

Alternatively put the comparison inside the definition of \car.

%\def\car{Yes}%% Not needed for this example
\def\iszero#1{%
  \edef\car{%
    \ifnum#1=0
      Yes%
    \else
      No%
    \fi
  }}

False: \iszero{1}\car

True: \iszero{0}\car

I use \edef to get only Yes orNo in \car. If \def is used there is a risk that the input is changed before evaluated, e.g. if the input is a counter.

0

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.