0

I want to define two macros x and y, such that both have some kind of implementation, but in the specific case where we call x on y, the result is different. For example, how do I have to change the following definition

\newcommand{\x}[1]{Foo #1}
\newcommand{\y}[1]{Bar #1}

to have the code

\x{SomeExpression}
\y{SomeExpression}
\x{\y{SomeExpression}}
\x{\y{SomeExpression}\y{SomeExpression}}

produce this output:

Foo ResultOfSomeExpression

Bar ResultOfSomeExpression

You called x after y

Foo Bar ResultOfSomeExpressionBar ResultOfSomeExpression

Here SomeExpression is an expression that evaluates to a a string ResultOfSomeExpression. I do not care what happens if you do such things as calling

\x{\y}

since it is not intended use in my application.

  • 1
    Why is \x{\y{a}}'s output different from \x{\y{a}\y{a}}, even though they both seem to fall under the "You called \x after \y" category? – Werner Nov 2 '16 at 20:07
  • The result shall only be different in the specific case where we concatenate x with y directly. – Oles Wohnzimmer Nov 2 '16 at 20:15
  • 1
    How is \y concatenated with \x directly in \x{\y{a}} and not \x{\y{a}\y{a}}? Perhaps I don't understand your use of "directly" (as opposed to indirectly?). – Werner Nov 2 '16 at 20:17
  • 2
    You are using "concatenate" in a strange way here normally it used in the sense of of conatenating two strings where each are arguments of the concatenation, but in your example \y{a} (not even just \y) is the argument of \x so you wouldn't nrmally say anything is concatenated. – David Carlisle Nov 2 '16 at 20:21
  • 2
    @OlesWohnzimmer: In my opinion, this remains clear as mud... Why? Because even after numerous attempts at clarifying, the only answer(er) still requires clarification as to whether the answer satisfies your needs. – Werner Nov 2 '16 at 20:34
5

enter image description here

\documentclass{article}
\begin{document}
\makeatletter
\newcommand{\x}[1]{%
\expandafter\def\expandafter\zz\expandafter{\@firstoftwo#1..}%
\ifx\z\zz 
You called x after y%
\else
Foo #1%
\fi}
\newcommand{\y}[1]{Bar #1}
\def\z{\y..}



\x{a}

\y{a}

\x{\y{a}}

\x{\y{a}\y{a}}

\x{SomeExpression}

\y{SomeExpression}

\x{\y{SomeExpression}}

\x{\y{SomeExpression}\y{SomeExpression}}
\end{document}
  • A problem with this approach is that it is specific to passing a as the argument to \y, and would therefore fail if you use \x{\y{b}}. – Werner Nov 2 '16 at 20:10
  • 1
    @Werner I'm not sure if that is a problem with this approach or a requirement. the problem specification wasn't that clear.... – David Carlisle Nov 2 '16 at 20:13
  • I try to make the specification more clear, but the way i meant it is as understood by Werner in his comment, your solution does not do what I want (But thanks for the fast respond!) – Oles Wohnzimmer Nov 2 '16 at 20:21
  • @OlesWohnzimmer your comment under the question doesn't really clarify it:-) do you als want \x{\y{b}} to make the special text? what about \x{\y} ? – David Carlisle Nov 2 '16 at 20:24
  • @OlesWohnzimmer updated answer, better? – David Carlisle Nov 2 '16 at 20:28
1

In TeX and LaTeX everything is about processing tokens, about expanding (expandable) macro tokens, etc.

Instead of properly specifying (in words) an algorithm that would describe the desired behavior of the macros \x and \y when processing their argument/the tokens of their argument, you just specified four cases of behavior:

  • Case 1: \x{SomeExpression}
                    → Foo ResultOfSomeExpression

  • Case 2: \y{SomeExpression}
                    → Bar ResultOfSomeExpression

  • Case 3: \x{\y{SomeExpression}}
                    → You called x after y

  • Case 4: \x{\y{SomeExpression}\y{SomeExpression}}
                    → Foo Bar ResultOfSomeExpressionBar ResultOfSomeExpression

Are you sure that in Case 4 you do wish the result
Foo Bar ResultOfSomeExpressionBar ResultOfSomeExpression
and you don't wish the result
Foo ResultOfBar ResultOfSomeExpressionBar ResultOfSomeExpression ?

Probably some parentheses would be nice indicating associativity? — Something like:
Foo ResultOf(Bar ResultOf(SomeExpression)Bar ResultOf(SomeExpression)) ?

Be that as it may.

Below I implemented a macro \y and a macro \x.

The macro \y just "grabs" its argument (whereby delimiting braces get removed) and returns that argument with the leading phrase Bar ResultOf added:
Bar ResultOf<Argument>.

The macro \x grabs its argument (whereby delimiting braces get removed) and forks three cases:

Case 1: Argument is of pattern
⟨control-sequence-token \y⟩ + ⟨single undelimited argument⟩
In that case you get the phrase: You called x after y .

Case 2: Argument is of pattern
⟨control-sequence-token \y⟩ + ⟨something that is not a single undelimited argument, could as well be emptiness⟩
In that case you get the phrase Foo <Argument>.

Case 3: Argument is of any other pattern, can as well be emptiness.
In that case you get the phrase Foo ResultOf<Argument>.

Be aware that neither did I use any eTeX-extensions or the like, nor did I use any \if..\else..\fi-tokens, nor do temporary assignments take place.

The circumstance that temporary assignments do not take place makes the macros usable in expansion-contexts as well.

E.g., if you have (e.g. in terms of \@namedef) defined a macro-token whose name is \You called x after y, you could call that macro via \csname\x{\y{something}}\endcsname.

\documentclass[a4paper]{article}
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@Exchange,
%%    \UD@CheckWhetherNull, \UD@CheckWhetherSingleUndelimitedArg
%%=============================================================================
\makeatletter
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
%% A concern in his posting is that the argument is hit with \string
%% after some expansions which in edge cases might result in unbalancing
%% surrounding \if..\fi-constructs if the macro is used inside of such
%% \if..\fi-constructs.
%%
%% That challenging concern sickened me. ;-)
%%
%% Therefore I decided to implerment a variant where this cannot happen
%% as expansion is forced by \romannumeral:
%%
%% After the first expansion-step, \string is not applied yet.
%% After the second expansion-step, any possibly disturbing remainders
%% are already removed due to \romannumeral-expansion.
%%
%% No eTeX- or whatsoever extensions. No \if.. .Only \romannumeral,
%% digit 0, space token for terminating \romannumeral-expansion,
%% \string, \expandafter, \UD@firstoftwo, \UD@secondoftwo, {, }.
%%
%% May 20, 2016
%%
%% Ulrich Diez (e-mail: ud.usenetcorrespondence@web.de)
%%
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% Check whether argument itself consists of exactly one undelimited 
%% argument:
%%.............................................................................
\newcommand\UD@CheckWhetherSingleDelimitedArg[1]{%
  \romannumeral0%
  \UD@CheckWhetherNull{#1}{\UD@secondoftwo{}}{%
    \expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
    {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
  }%
  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%=============================================================================
%% Internal macros of a mechanism checking whether a macro argument is of
%% pattern \y<single undelimited argument> -- the user-level-macro will be
%% \UDAtCheckWhetherLeadingyAndSingleUndelimited 
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument starts with a \y-token
%%.............................................................................
%% \UDAtCheckWhetherLeadingy{<Argument which is to be checked>}%
%%                         {<Tokens to be delivered in case <argument
%%                            which is to be checked>'s 1st token is a
%%                            \y-token>}%
%%                         {<Tokens to be delivered in case <argument
%%                           which is to be checked>'s 1st token is not
%%                           a \y-token>}%
\newcommand\UDAtCheckWhetherLeadingy[1]{%
  \romannumeral0\UD@CheckWhetherNull{#1}%
  {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
  {\expandafter\UD@secondoftwo\string{\UD@CheckWhetherLeadingyB.#1\y}{}}%
}%
\newcommand\UD@CheckWhetherLeadingyB{}%
\long\def\UD@CheckWhetherLeadingyB#1\y{%
  \expandafter\UD@CheckWhetherNull\expandafter{\UD@secondoftwo#1{}}%
  {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
  {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
   \expandafter\expandafter\expandafter}\expandafter\expandafter
   \expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
}%
%%-----------------------------------------------------------------------------
%% Check whether brace-balanced argument is of pattern
%% \y<single undelimited argument>
%%.............................................................................
\newcommand\UDAtCheckWhetherLeadingyAndSingleUndelimited[1]{%
  \romannumeral0%
  \UDAtCheckWhetherLeadingy{#1}{%
    \expandafter\UD@CheckWhetherSingleDelimitedArg
    \expandafter{\UD@firstoftwo{}#1}{%
      \expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo        
    }%
  }{\UD@secondoftwo{}}%
  {%
    \expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo
  }%
}%
\makeatother

%% This delivers the texts that you specified.

\newcommand\x[1]{%
  \UDAtCheckWhetherLeadingyAndSingleUndelimited{#1}{%
    You called x after y%
  }{%
   \UDAtCheckWhetherLeadingy{#1}{Foo #1}{Foo ResultOf#1}%
  }%
}%
\newcommand\y[1]{Bar ResultOf#1}%    

%%\newcommand\x[1]{%
%%  \UDAtCheckWhetherLeadingyAndSingleUndelimited{#1}{%
%%    operation x with the result of applying operation y to #1 as operand%
%%  }{%
%%   operation x with operand (#1)%
%%  }%
%%}%
%%
%%newcommand\y[1]{operation y with operand (#1)}%


\begin{document}

\x{SomeExpression}

\y{SomeExpression}

\x{\y{SomeExpression}}

\x{\y{SomeExpression}\y{SomeExpression}}

\makeatletter
\@namedef{You called x after y}{Calling x after y is nice!}
\@namedef{Foo ResultOfSomethingWeird}{Calling x on something weird is nice too!}
\@namedef{Bar ResultOfSomethingWeird}{Calling y on something weird is nice as well!}    
\@namedef{Foo Bar ResultOfSomethingWeirdBar ResultOfSomethingWeird}{Calling x on the square of result of calling y on something weird is extraordinarily nice!}        
\makeatother

\csname\x{\y{something weird}}\endcsname

\csname\x{SomethingWeird}\endcsname

\csname\y{SomethingWeird}\endcsname    

\csname\x{\y{SomethingWeird}\y{SomethingWeird}}\endcsname        

\end{document}
  • Dear OP, it seems like you have two accounts and therefore cannot edit your own posts - or, for that matter, earn rep and interact with the site in a meaningful way. I highly recommend getting in contact with a moderator and having your accounts merged so that you can get the most out of the site and make corrections to your posts :) – Au101 Nov 4 '16 at 19:36

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.