Your comment
Thank you for your answer! That "lambda-caculusish" trick has been
mentionned in the discussion below the accepted post, but thanks
anyway for mentionning it. Furthermore, the idea of having optionnal
arguments to have a two-sided funtion, 50% normal, 50%
"functorized" is absolutely great. Thanks for the tip!
caused me to add a few remarks to my answer:
You program in LaTeX. LaTeX is based on TeX as described in the TeXbook of Donald Ervin Knuth. Basically LaTeX is just a set of macros written in TeX and packaged as a so-called format in order to have these macros loaded automatically when loading the TeX-program via an executable that is called latex/latex.exe/whatsoever.
Low-level-concepts introduced in the TeXbook also apply to LaTeX.
Thus in the following explanations things where I use the phrase "TeX" also apply when programming in LaTeX.
In my explanations below I nowhere use the word "function". I don't do so because—desite expl3's misleading (in my opinion ;-) ) terminology where the word "function" is used a lot—the programming-paradigma of TeX is not a procedural/functional one as is the case with high level programming languages like Pascal, C++ or Java, but is rather a macro-based declarative and symbolic one, where the symbols are formed by so-called tokens and where symbols/tokens get replaced by other symbols/tokens during the stage of expansion.
When I started with TeX and LaTeX, I tried to immediately transfer the things I knew about programming in higher languages like Pascal, C ++ and Java to TeX/LaTeX.
I didn't do myself a favor with it. It made my TeX/LaTeX-learning-curve unnecessarily steep.
At that time it was not clear to me that the transfer should go hand in hand with transferring the concepts and terms of one programming paradigm to another completely different programming paradigm.
I think such transferring-attempts cannot work well when still in a stage of learning and getting familiar with the concepts and terms of one of the programming-paradigms involved.
I think such transferring-attempts only work well if you are very familiar with the concepts and terms of both programming paradigms.
That is why I believe that it is better, at least at the beginning of learning TeX/LaTeX, to stick strictly to the terms that belong to the programming paradigm underlying TeX/LaTeX and to avoid "borrowing" terms that belong to other programming paradigms.
In Knuth's analogy to a digestive process TeX has
- eyes
- a digestive tract
- the ability to produce tokens and put them into its mouth where the digestion process begins.
TeX's eyes read the .tex-input-file. Hereby TeX takes the input for a set of instructions for producing tokens and putting these tokens into its mouth one by one. So the tokens form a "token-stream" whose elements one by one are lead through TeX's digestive tract. Tokens can be control-sequence-tokens in different flavors or character-tokens in different flavors.
Producing tokens from the instructions formed by .tex-input-files takes place according to rules provided by characters' category-codes, by values of parameters like \endlinechar
and by things that are "hardcoded" into the TeX-program (or LaTeX-program, if you use the variant where the set of macros that forms the LaTeX-format is loaded automatically).
Expansion of a(n expandable) token—i.e., replacement of that token (and probably those tokens that form its arguments) by other tokens—takes place while tokens are transported through TeX's gullet.
Assignments (defining macros, assigning values to \count
-registers and the like) in that analogy take place in TeX's stomach.
The final result of TeX's digestion-process will be the output-files (.pdf-file/.dvi-file, .log-file, auxiliary text files like the .aux-files and .toc-file and .lot/.lof-file etc) and things that are written to the console.
After this very rough overview of things let's go back to the stage of expansion of expandable tokens which takes place in TeX's gullet:
Think of TeX-macros as tokens that during expansion get removed from the token-stream and which additionally trigger the removal of more tokens from the token-stream followed by insertion of tokens into the token-stream. "Removal of more tokens from the token-stream" is done according to the rules provided by the ⟨parameter text⟩ which belongs to the macro's ⟨definition⟩. "Insertion of tokens into the token-stream" is done according to the rules provided by the ⟨balanced text⟩ which also belongs to the macro's ⟨definition⟩. The tokens inserted into the token-stream form the "replacement text".
With \newcommand{\b}[N]{{\b1{...}}...{\bn{...}}}
and with ...
being the arguments of \b
which are to be passed to macros \b1
, .... , \bn
you ask for \b1
, .... , \bn
to be changeable without further tricks although being tokens that are part of the ⟨balanced text⟩ of the definition of macro \b
.
But this is not possible without further expansion-tricks:
Tokens [—other than the sequences #1
, #2
, ..., #9
that denote arguments that are to be gathered from the token-stream's subsequent tokens according to the ⟨parameter text⟩ and other than sequences ##
that will be reduced to #
, which is useful for nesting ⟨definition⟩s inside the ⟨balanced text⟩ of other ⟨definition⟩s—] that come from the ⟨balanced text⟩ of a macro's ⟨definition⟩ (as would be the case with \b1
,...,\bn
) do not get changed/replaced at the time when expanding that macro (in this case the macro \b
) leads to inserting the replacement text into the token-stream.
What can be done by means of macros and macro-expansion?
You wish to apply \name
to the replacement text of \tunnel
?
Rephrased: Expanding \tunnel
shall lead to the insertion of tokens into the token-stream that are to be used as arguments of \name
?
As already mentioned in a comment by David Carlisle to the accepted post and as in your reply to that comment called a "lambda-calculus-like method", you can define \tunnel
with an argument where you can pass a macro-token which shall process the arguments delivered by \tunnel
.
I now add that that argument can be an optional one which by default is empty:
\documentclass{article}
\newcommand{\tunnel}[3][]{#1{#2}{#3}}
\newcommand{\name}[2]{\textbf{#1}~\textit{#2}}
\begin{document}
Desired output is \name{hello}{you}
Actual output is \tunnel[\name]{hello}{you}
\end{document}
By means of a little helper-macro, called \PassArgumentToMacroAndThenDo
, with \tunnel
you can also pass things to more than one macro:
\documentclass{article}
\newcommand\PassArgumentToMacroAndThenDo[3]{%
%#1 <Macro> which shall process argument #3 as its first/only argument.
%#2 Tokens to insert behind the sequence <Macro>{Argument3} .
%#3 Element of a list of Arguments that are to be processed by <Macro>s.
#1{#3}#2%
}%
\newcommand\ProcessFirstArg[1]{\par\noindent First Arg processed by \texttt{\string\ProcessFirstArg}: #1.}
\newcommand\ProcessSecondArg[1]{\par\noindent Second Arg processed by \texttt{\string\ProcessSecondArg}: #1.}
\newcommand\ProcessThirdArg[1]{\par\noindent Third Arg processed by \texttt{\string\ProcessThirdArg}: #1.}
\newcommand\ProcessFourthArg[1]{\par\noindent Fourth Arg processed by \texttt{\string\ProcessFourthArg}: #1.}
\newcommand\ProcessFifthArg[1]{\par\noindent Fifth Arg processed by \texttt{\string\ProcessFifthArg}: #1.}
\newcommand\ProcessSixthArg[1]{\par\noindent Sixth Arg processed by \texttt{\string\ProcessSixthArg}: #1.}
\newcommand\ProcessSeventhArg[1]{\par\noindent Seventh Arg processed by \texttt{\string\ProcessSeventhArg}: #1.}
\newcommand\ProcessEighthArg[1]{\par\noindent Eighth Arg processed by \texttt{\string\ProcessEighthArg}: #1.}
\newcommand{\tunnel}[9][]{#1{\texttt{\string\tunnel}-processed-#2}%
{\texttt{\string\tunnel}-processed-#3}%
{\texttt{\string\tunnel}-processed-#4}%
{\texttt{\string\tunnel}-processed-#5}%
{\texttt{\string\tunnel}-processed-#6}%
{\texttt{\string\tunnel}-processed-#7}%
{\texttt{\string\tunnel}-processed-#8}%
{\texttt{\string\tunnel}-processed-#9}}
\begin{document}
\PassArgumentToMacroAndThenDo\ProcessFirstArg{%
\PassArgumentToMacroAndThenDo\ProcessSecondArg{%
\PassArgumentToMacroAndThenDo\ProcessThirdArg{%
\PassArgumentToMacroAndThenDo\ProcessFourthArg{%
\PassArgumentToMacroAndThenDo\ProcessFifthArg{%
\PassArgumentToMacroAndThenDo\ProcessSixthArg{%
\PassArgumentToMacroAndThenDo\ProcessSeventhArg{%
\PassArgumentToMacroAndThenDo\ProcessEighthArg{%
}%
}%
}%
}%
}%
}%
}%
}%
{A}{B}{C}{D}{E}{F}{G}{H}
\bigskip
\tunnel{A}{B}{C}{D}{E}{F}{G}{H}
\bigskip
\tunnel[%
\PassArgumentToMacroAndThenDo\ProcessFirstArg{%
\PassArgumentToMacroAndThenDo\ProcessSecondArg{%
\PassArgumentToMacroAndThenDo\ProcessThirdArg{%
\PassArgumentToMacroAndThenDo\ProcessFourthArg{%
\PassArgumentToMacroAndThenDo\ProcessFifthArg{%
\PassArgumentToMacroAndThenDo\ProcessSixthArg{%
\PassArgumentToMacroAndThenDo\ProcessSeventhArg{%
\PassArgumentToMacroAndThenDo\ProcessEighthArg{%
}%
}%
}%
}%
}%
}%
}%
}%
]{A}{B}{C}{D}{E}{F}{G}{H}
\end{document}
By means of yet another helper-macro-mechanism which is based on \ronannumeral0
-expansion and which does recursively collect an arbitrary amount of arguments which can be specified by the user, you can arrange things in ways where each of the things that can be passed to macros by \tunnel
do not necessarily need to consist of a single argument only:
\documentclass{article}
\makeatletter
\newcommand\PassKArgumentsToMacroAndThenDo[3]{%
%#1 TeX <number>-quantity denoting the non-negative integer-number <K>.
%#2 <Macro> which shall process next <K> Arguments.
%#3 Tokens to insert behind the sequence <Macro>{Argument1}..{ArgumentK} .
\romannumeral0\expandafter\PassKArgumentsToMacroAndThenDoLoop\expandafter{\romannumeral0\number\number#1 000}{#2}{#3}{}%
}%
\newcommand\PassKArgumentsToMacroAndThenDoLoop[4]{%
%#1 Sequence of letters m in the amount of arguments to collect
%#2 <Macro> which shall process next <K> Arguments
%#3 Tokens to insert behind the sequence <Macro>{Argument1}..{ArgumentK}
%#4 Arguments collected so far
\ifx D#1D\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{ #2#4#3}%
{\PassKArgumentsToMacroAndThenDoLoopFetchNextArg{#1}{#2}{#3}{#4}}%
}%
\newcommand\PassKArgumentsToMacroAndThenDoLoopFetchNextArg[5]{%
%#1 Sequence of letters m in the amount of arguments to collect
%#2 <Macro> which shall process next <K> Arguments
%#3 Tokens to insert behind the sequence <Macro>{Argument1}..{ArgumentK}
%#4 Arguments collected so far
%#5 Next argument
\expandafter\PassKArgumentsToMacroAndThenDoLoop\expandafter{\@firstoftwo{}#1}{#2}{#3}{#4{#5}}%
}%
\makeatother
\newcommand\ProcessFirstAndSecondArg[2]{%
\par\noindent First Arg processed by \texttt{\string\ProcessFirstAndSecondArg}: #1.%
\par\noindent Second Arg processed by \texttt{\string\ProcessFirstAndSecondArg}: #2.%
}%
\newcommand\ProcessThirdAndFourthAndFifthArg[3]{%
\par\noindent Third Arg processed by \texttt{\string\ProcessThirdAndFourthAndFifthArg}: #1.%
\par\noindent Fourth Arg processed by \texttt{\string\ProcessThirdAndFourthAndFifthArg}: #2.%
\par\noindent Fifth Arg processed by \texttt{\string\ProcessThirdAndFourthAndFifthArg}: #3.%
}%
\newcommand\ProcessSixthSeventhAndEighthArg[3]{%
\par\noindent Sixth Arg processed by \texttt{\string\ProcessSixthSeventhAndEighthArg}: #1.%
\par\noindent Seventh Arg processed by \texttt{\string\ProcessSixthSeventhAndEighthArg}: #2.%
\par\noindent Eighth Arg processed by \texttt{\string\ProcessSixthSeventhAndEighthArg}: #3.%
}
\newcommand{\tunnel}[9][]{#1{\texttt{\string\tunnel}-processed-#2}%
{\texttt{\string\tunnel}-processed-#3}%
{\texttt{\string\tunnel}-processed-#4}%
{\texttt{\string\tunnel}-processed-#5}%
{\texttt{\string\tunnel}-processed-#6}%
{\texttt{\string\tunnel}-processed-#7}%
{\texttt{\string\tunnel}-processed-#8}%
{\texttt{\string\tunnel}-processed-#9}}
\begin{document}
\PassKArgumentsToMacroAndThenDo{2}\ProcessFirstAndSecondArg{%
\PassKArgumentsToMacroAndThenDo{3}\ProcessThirdAndFourthAndFifthArg{%
\PassKArgumentsToMacroAndThenDo{3}\ProcessSixthSeventhAndEighthArg{%
}%
}%
}%
{A}{B}{C}{D}{E}{F}{G}{H}
\bigskip
\tunnel{A}{B}{C}{D}{E}{F}{G}{H}
\bigskip
\tunnel[%
\PassKArgumentsToMacroAndThenDo{2}\ProcessFirstAndSecondArg{%
\PassKArgumentsToMacroAndThenDo{3}\ProcessThirdAndFourthAndFifthArg{%
\PassKArgumentsToMacroAndThenDo{3}\ProcessSixthSeventhAndEighthArg{%
}%
}%
}%
]{A}{B}{C}{D}{E}{F}{G}{H}
\end{document}
\expandafter
primitive for example). Even in your "simple"\a{\b{...}}
example, there is no guarantee that\a
will be happy with\b{...}
as an argument. In fact, it often will not be.\expandafter\name\tunnel{hello}{you}
\a{\b{...}}
with n = 1 could fail! Thanks for your answer, really appreciate it. I'll take a look at the\exandafter
command.\a
is literally\b{...}
not the expansion of\b
so it will fail or not depending if it is expecting commands or simply text. (actually I can think of no computer programming language or formal system that works the way you seem to expect where you can put a term as the first argument of a function and it supplies values for the first and second arguments.)