summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2022-03-11 23:36:45 +0000
committerKarl Berry <karl@freefriends.org>2022-03-11 23:36:45 +0000
commitc625aafbd0a1793c16269556c2bb7b12b5e1abdc (patch)
tree73c6963fad558df08887ebf1dd8e553d1c75485e
parent41bf581d1e01e395d0eaeb2fc50b36d0cd3c92bc (diff)
functional (branch)
git-svn-id: svn://tug.org/texlive/branches/branch2021.final@62648 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Master/texmf-dist/doc/latex/functional/README.txt5
-rw-r--r--Master/texmf-dist/doc/latex/functional/functional.pdfbin0 -> 189483 bytes
-rw-r--r--Master/texmf-dist/doc/latex/functional/functional.tex994
-rw-r--r--Master/texmf-dist/tex/latex/functional/functional.sty686
-rw-r--r--Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/functional.tlpsrc0
6 files changed, 1686 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/latex/functional/README.txt b/Master/texmf-dist/doc/latex/functional/README.txt
new file mode 100644
index 00000000000..fcb1672c0c3
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/functional/README.txt
@@ -0,0 +1,5 @@
+Functional: LaTeX2 functional interfaces to LaTeX3 programming layer
+Copyright : 2022 (c) Jianrui Lyu <tolvjr@163.com>
+Repository: https://github.com/lvjr/functional
+Repository: https://bitbucket.org/lvjr/functional
+License : The LaTeX Project Public License 1.3c
diff --git a/Master/texmf-dist/doc/latex/functional/functional.pdf b/Master/texmf-dist/doc/latex/functional/functional.pdf
new file mode 100644
index 00000000000..f9f553a0daa
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/functional/functional.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/functional/functional.tex b/Master/texmf-dist/doc/latex/functional/functional.tex
new file mode 100644
index 00000000000..18dfa306621
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/functional/functional.tex
@@ -0,0 +1,994 @@
+% -*- coding: utf-8 -*-
+
+\documentclass[oneside]{book}
+\usepackage[a4paper,margin=2.5cm]{geometry}
+
+\newcommand*{\myversion}{2022A}
+\newcommand*{\mydate}{Version \myversion\ (\the\year-\mylpad\month-\mylpad\day)}
+\newcommand*{\mylpad}[1]{\ifnum#1<10 0\the#1\else\the#1\fi}
+
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{4pt plus 1pt minus 1pt}
+
+\usepackage{codehigh}
+
+\colorlet{highback}{blue9}
+%\CodeHigh{lite}
+\CodeHigh{language=latex/latex2,style/main=highback,style/code=highback}
+\NewCodeHighEnv{code}{style/main=gray9,style/code=gray9}
+\NewCodeHighEnv{demo}{style/main=gray9,style/code=gray9,demo}
+
+\NewDocumentCommand\MySubScript{m}{$_{#1}$}
+
+\ExplSyntaxOn
+\NewDocumentCommand\PrintVarList{m}{
+ \clist_set:Nn \l_tmpa_clist {#1}
+ \clist_map_inline:Nn \l_tmpa_clist
+ {
+ \token_to_str:N ##1 ~
+ }
+}
+\NewDocumentCommand\RelaceChacters{m}{
+ \tl_set:Nn \lTmpaTl {#1}
+ \regex_replace_once:nnN { \_ } { \c{MySubScript} } \lTmpaTl
+}
+\ExplSyntaxOff
+
+\NewDocumentEnvironment{variable}{m}{
+ \vspace{5pt}
+ \begin{minipage}{\linewidth}
+ \hrule\vspace{4pt}\obeylines%
+ \begingroup
+ \ttfamily\bfseries\color{azure3}
+ \PrintVarList{#1}
+ \endgroup
+ \par\vspace{4pt}\hrule
+ \end{minipage}\par\nopagebreak\vspace{4pt}
+}{%
+ \vspace{5pt}%
+}
+
+\NewDocumentEnvironment{function}{m}{
+ \vspace{5pt}%
+}{\vspace{5pt}}
+
+\NewDocumentEnvironment{syntax}{}{%
+ \begin{minipage}{\linewidth}
+ \hrule\vspace{4pt}\obeylines%
+}{%
+ \par\vspace{4pt}\hrule
+ \end{minipage}\par\nopagebreak\vspace{4pt}
+}
+
+\NewDocumentEnvironment{texnote}{}{}{}
+
+\NewDocumentCommand\cs{m}{%
+ \texttt{\bfseries\color{purple3}\expandafter\string\csname#1\endcsname}%
+}
+\NewDocumentCommand\meta{m}{%
+ \RelaceChacters{#1}%
+ \textsl{$\langle$\ignorespaces\lTmpaTl\unskip$\rangle$}%
+}
+\NewDocumentCommand\Arg{m}{%
+ \RelaceChacters{#1}%
+ \texttt{\{}\textsl{$\langle$\ignorespaces\lTmpaTl\unskip$\rangle$}\texttt{\}}%
+}
+
+\let\tn=\cs
+
+\RenewDocumentCommand\emph{m}{%
+ \underline{\textsl{#1}}%
+}
+
+\usepackage{hyperref}
+\hypersetup{
+ colorlinks=true,
+ urlcolor=blue3,
+ linkcolor=blue3,
+}
+
+\usepackage{functional}
+%\Functional{scoping=false,tracing=true}
+
+\begin{document}
+
+\title{\sffamily LaTeX2 \textcolor{green3}{Functional} Interfaces to LaTeX3 Programming Layer}
+\author{Jianrui Lyu (tolvjr@163.com)\\\url{https://github.com/lvjr/functional}}
+\date{\mydate\vspace{1cm}\\\myabstract\vspace{10cm}}
+
+\newcommand\myabstract{\parbox{\linewidth}{\hrule\vspace{0.8em}\large
+LaTeX3 programming layer (\textsf{expl3}) is very powerful for advanced users,
+but it is a little complicated for normal users.
+This \textcolor{green3}{\sffamily functional} package aims to provide
+intuitive LaTeX2 functional interfaces for it.
+\par\vspace{0.5em}
+Although there are functions in LaTeX3, the evaluation of them is from outside to inside.
+With this package, the evaluation of functions is from inside to outside,
+which is the same as other programming languages such as \texttt{JavaScript} or \texttt{Lua}.
+In this way, it is rather easy to debug code too.
+\par\vspace{0.5em}
+Note that many paragraphs in this manual are copied from the documentation of \textsf{expl3}.
+\par\vspace{0.8em}\hrule}}
+
+{\let\newpage\relax\vspace{-4cm}\maketitle}
+
+\tableofcontents
+
+\chapter{Overview of Features}
+
+\section{Evaluation from Inside to Outside}
+
+We will compare our first example with a similar \verb!Lua! example:
+
+\begin{code}
+-- lua code --
+function MathSquare (arg)
+ local lTmpaInt = arg * arg
+ return lTmpaInt
+end
+print(MathSquare(5))
+print(MathSquare(MathSquare(5)))
+\end{code}
+
+\begin{codehigh}
+%% function code
+\ExplSyntaxOn
+\PrgNewFunction \MathSquare { m } {
+ \IntSet \lTmpaInt { \IntEval { #1 * #1 } }
+ \Result { \Value \lTmpaInt }
+}
+\ExplSyntaxOff
+\MathSquare{5}
+\MathSquare{\MathSquare{5}}
+\end{codehigh}
+
+%\ExplSyntaxOn
+%\PrgNewFunction \MathSquare { m }{
+% \IntSet \lTmpaInt { \IntEval { #1 * #1 } }
+% \Result { \Value \lTmpaInt }
+%}
+%\ExplSyntaxOff
+%\MathSquare{5}
+%\MathSquare{\MathSquare{5}}
+
+%\ExplSyntaxOn
+%\PrgNewFunction \MathCubic { m }
+% {
+% \IntSet \lTmpaInt { \IntEval { #1 * #1 * #1 } }
+% \Result { \Value \lTmpaInt }
+% }
+%\ExplSyntaxOff
+%\MathCubic{2}
+%\MathCubic{\MathCubic{2}}
+
+Both examples calculate first the square of $5$ and produce $25$,
+then calculate the square of $25$ and produce $625$.
+In contrast to \verb!expl3!, this \verb!functional! package
+does evaluation of functions from inside to outside,
+which means composition of functions works like othe programming languages
+such as \verb!Lua! or \verb!JavsScript!.
+
+You can define new functions with \cs{PrgNewFunction} command.
+To make composition of functions work as expected,
+every function \emph{must not} insert directly any token to the input stream.
+Instead, a function \emph{must} pass the result (if any) to \verb!functional! package
+with \cs{Result} command. And \verb!functional! package is responsible for
+inserting result tokens to the input stream at the appropriate time.
+
+To remove space tokens inside function code in defining functions,
+you'd better put function definitions inside \verb!\ExplSyntaxOn! and
+\verb!\ExplSyntaxOff! block. Within this block, \verb!~! is used to input a space.
+
+At the end of this section,
+we will compare our factorial example with a similar \verb!Lua! example:
+
+\begin{code}
+-- lua code --
+function Factorial (n)
+ if n == 0 then
+ return 1
+ else
+ return n * Factorial(n-1)
+ end
+end
+print(Factorial(4))
+\end{code}
+
+\begin{codehigh}
+\ExplSyntaxOn
+\PrgNewFunction \Factorial { m } {
+ \IntCompareTF {#1} = {0} {
+ \Result {1}
+ }{
+ \Result { \IntMathMult {#1} { \Factorial { \IntMathSub{#1}{1} } } }
+ }
+}
+\ExplSyntaxOff
+\Factorial{4}
+\end{codehigh}
+
+%\ExplSyntaxOn
+%\PrgNewFunction \Factorial { m } {
+% \IntCompareTF {#1} = {0} {
+% \Result {1}
+% }{
+% \Result { \IntMathMult {#1} { \Factorial { \IntMathSub{#1}{1} } } }
+% }
+%}
+%\ExplSyntaxOff
+%\Factorial{0}
+%\Factorial{4}
+
+\section{Group Scoping of Functions}
+
+In \verb!Lua! language, a function or a condition expression makes a block,
+and the values of local variables will be reset after a block.
+For example
+
+\begin{code}
+-- lua code --
+local a = 1
+print(a) ---- 1
+function SomeFun()
+ local a = 2
+ print(a) ---- 2
+ if 1 > 0 then
+ local a = 3
+ print(a) ---- 3
+ end
+ print(a) ---- 2
+end
+SomeFun()
+print(a) ---- 1
+\end{code}
+
+In \verb!functional! package, a condition expression is in fact a function,
+and you can make every function become a group by setting
+\verb!\Functional{scoping=true}!. For example
+
+\begin{codehigh}
+\Functional{scoping=true}
+\ExplSyntaxOn
+\IntSet \lTmpaInt {1}
+\IntLog \lTmpaInt % ---- 1
+\PrgNewFunction \SomeFun { } {
+ \IntSet \lTmpaInt {2}
+ \IntLog \lTmpaInt % ---- 2
+ \IntCompareTF {1} > {0} {
+ \IntSet \lTmpaInt {3}
+ \IntLog \lTmpaInt % ---- 3
+ }{ }
+ \IntLog \lTmpaInt % ---- 2
+}
+\SomeFun
+\IntLog \lTmpaInt % ---- 1
+\ExplSyntaxOff
+\end{codehigh}
+
+Same as \verb!expl3!, the names of local variables \emph{must} start with \verb!l!,
+while names of global variables \emph{must} start with \verb!g!.
+The difference is that \verb!functional! package provides only one function for setting
+both local and global varianbles of the same type,
+by checking leading letters of their names. So for integer variables, you can write
+\verb!\IntSet\lTmpaInt{1}! and \verb!\IntSet\gTmpbInt{2}!.
+
+The previous example will produce different result
+if we change variable from \verb!\lTmpaInt! to \verb!\gTmpaInt!.
+
+\begin{codehigh}
+\Functional{scoping=true}
+\IntSet \gTmpaInt {1}
+\IntLog \gTmpaInt % ---- 1
+\PrgNewFunction \SomeFun { } {
+ \IntSet \gTmpaInt {2}
+ \IntLog \gTmpaInt % ---- 2
+ \IntCompareTF {1} > {0} {
+ \IntSet \gTmpaInt {3}
+ \IntLog \gTmpaInt % ---- 3
+ }{ }
+ \IntLog \gTmpaInt % ---- 3
+}
+\SomeFun
+\IntLog \gTmpaInt % ---- 3
+\end{codehigh}
+
+As you can see, the values of global variables will never be reset after a group.
+
+\section{Tracing Evaluation of Functions}
+
+Since every function in \verb!functional! package will pass its return value to
+the package, it is quite easy to debug your code.
+You can turn on the tracing by setting \verb!\Functional{tracing=true}!.
+For example, the tracing log of the first example in this chapter will be the following:
+
+% FIXME: spaces at the first line will be removed
+%\begin{codehigh}[]
+% [I] \MathSquare{5}
+% [I] \IntEval{5*5}
+% [I] \Expand{\int_eval:n {5*5}}
+% [O] 25
+% [I] \Result{25}
+% [O] 25
+% [O] 25
+% [I] \IntSet\lTmpaInt {25}
+% [O]
+% [I] \Value\lTmpaInt
+% [O] 25
+% [I] \Result{25}
+% [O] 25
+% [O] 25
+%\end{codehigh}
+\begin{codehigh}[]
+[I] \MathSquare{5}
+ [I] \IntEval{5*5}
+ [I] \Expand{\int_eval:n {5*5}}
+ [O] 25
+ [I] \Result{25}
+ [O] 25
+ [O] 25
+ [I] \IntSet\lTmpaInt {25}
+ [O]
+ [I] \Value\lTmpaInt
+ [O] 25
+ [I] \Result{25}
+ [O] 25
+[O] 25
+[I] \MathSquare{25}
+ [I] \IntEval{25*25}
+ [I] \Expand{\int_eval:n {25*25}}
+ [O] 625
+ [I] \Result{625}
+ [O] 625
+ [O] 625
+ [I] \IntSet\lTmpaInt {625}
+ [O]
+ [I] \Value\lTmpaInt
+ [O] 625
+ [I] \Result{625}
+ [O] 625
+[O] 625
+\end{codehigh}
+
+\section{Definitions of Functions}
+
+Within \verb!expl3!, there are eight commands for defining new functions,
+which is good for power users.
+
+\begin{code}[language=latex/latex3]
+\cs_new:Npn
+\cs_new_nopar:Npn
+\cs_new_protected:Npn
+\cs_new_protected_nopar:Npn
+\cs_new:Nn
+\cs_new_nopar:Nn
+\cs_new_protected:Nn
+\cs_new_protected_nopar:Nn
+\end{code}
+
+Within \verb!functional! package, there is only one command (\cs{PrgNewFunction})
+for defining new functions, which is good for normal users.
+The created functions are always protected and accept \verb!\par! in their arguments.
+
+Since \verb!functional! package gets the results of functions by evaluation
+(including expansion and execution by \TeX), it is natural to protect all functions.
+
+\section{Variants of Arguments}
+
+Within \verb!expl3!, there are several expansion variants for arguments,
+and many expansion functions for expanding them, which are necessary for power users.
+
+\begin{code}[language=latex/latex3]
+\module_foo:c
+\module_bar:e
+\module_bar:x
+\module_bar:f
+\module_bar:o
+\module_bar:V
+\module_bar:v
+\end{code}
+
+\begin{code}[language=latex/latex3]
+\exp_args:Nc
+\exp_args:Ne
+\exp_args:Nx
+\exp_args:Nf
+\exp_args:No
+\exp_args:NV
+\exp_args:Nv
+\end{code}
+
+Within \verb!functional! package, there are only three variants
+(\verb!c!, \verb!e!, \verb!V!) are provided, and these variants are defined
+as functions (\cs{Name}, \cs{Expand}, \cs{Value}, respetively),
+which are easier to use for normal users.
+
+\begin{demohigh}
+\newcommand\test{uvw}
+\Name{test}
+\end{demohigh}
+
+\begin{demohigh}
+\newcommand\test{uvw}
+\Expand{111\test222}
+\end{demohigh}
+
+\begin{demohigh}
+\IntSet\lTmpaInt{123}
+\Value\lTmpaInt
+\end{demohigh}
+
+The most interesting feature is that you can compose these functions.
+For example, you can easily get the \verb!v! variant of \verb!expl3! by
+simply composing \cs{Name} and \cs{Value} functions:
+
+\begin{demohigh}
+\IntSet\lTmpaInt{123}
+\Value{\Name{lTmpaInt}}
+\end{demohigh}
+
+\chapter{Basic Definitions (\texttt{l3basics})}
+
+\section{Deļ¬ning Functions and Conditionals}
+
+\begin{function}{\PrgNewFunction}
+\begin{syntax}
+\cs{PrgNewFunction} \meta{function} \Arg{argument specification} \Arg{code}
+\end{syntax}
+Creates protected \meta{function} for evaluating the \meta{code}.
+Within the \meta{code}, the parameters (\verb|#1|, \verb|#2|,
+\emph{etc.}) will be replaced by those absorbed by the function.
+The returned value \emph{must} be passed with \cs{Result} function.
+The definition is global and an error results if the
+\meta{function} is already defined.\par
+The \Arg{argument specification} in a list of letters,
+where each letter is one of the following argument specifiers
+(nearly all of them are \texttt{M} or \texttt{m} for functions provided by this package):\par
+{\centering\begin{tabular}{ll}
+%\hline
+ \texttt{M} & single-token argument, which will be manipulated first \\
+ \texttt{m} & multi-token argument, which will be manipulated first \\
+ \texttt{N} & single-token argument, which will not be manipulated first \\
+ \texttt{n} & multi-token argument, which will not be manipulated first \\
+%\hline
+\end{tabular}\par}
+The argument manipulation for argument type \texttt{M} or \texttt{m}
+is: if the argument starts with a function defined with \cs{PrgNewFunction},
+the argument will be evaluated and replaced with the returned value.
+\end{function}
+
+\begin{function}{\PrgNewConditional}
+\begin{syntax}
+\cs{PrgNewConditional} \meta{function} \Arg{argument specification} \Arg{code}
+\end{syntax}
+Creates protected conditional \meta{function} for evaluating the \meta{code}.
+The returned value of the \meta{function} \emph{must} be either \verb!\cTrueBool!
+or \verb!\cFalseBool! and be passed with \cs{Result} function..
+The definition is global and an error results if the \meta{function} is already defined.
+\par
+Assume the \meta{function} is \verb!\FooIfBar!, then another function \verb!\FooIfBarTF!
+will be created at the same time. \verb!\FooIfBarTF! function has two extra arguments
+which are \Arg{true code} and \Arg{false code}.\par
+\end{function}
+
+\begin{function}{\Result}
+\begin{syntax}
+\cs{Result} \Arg{tokens}
+\end{syntax}
+Appends \meta{tokens} to \verb!\gResultTl!, which holds the returned value of current function.
+This function is normally used in the \meta{code} of \cs{PrgNewFunction} and \cs{PrgNewConditional}.
+\end{function}
+
+\section{Expanding and Using Tokens}
+
+\begin{function}{\Name}
+\begin{syntax}
+\cs{Name} \Arg{control sequence name}
+\end{syntax}
+Expands the \meta{control sequence name} until only characters
+remain, then converts this into a control sequence and returns it.
+The \meta{control sequence name} must consist of character tokens %,
+%typically a mixture of category code $10$ (space), $11$ (letter) and $12$ (other).
+when exhaustively expanded.%
+%\begin{texnote}
+%Protected macros that appear in a \texttt{c}-type argument are
+%expanded despite being protected; \cs{exp_not:n} also has no
+%effect. An internal error occurs if non-characters or active
+%characters remain after full expansion, as the conversion to a
+%control sequence is not possible.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\Value}
+\begin{syntax}
+\cs{Value} \meta{variable}
+\end{syntax}
+Recovers the content of a \meta{variable} and returns the value.
+An error is raised if the variable does not exist or if it is invalid.
+Note that it is the same as \cs{TlUse} for \meta{tl var}, or \cs{IntUse} for \meta{int var}.
+\end{function}
+
+\begin{function}{\Expand}
+\begin{syntax}
+\cs{Expand} \Arg{tokens}
+\end{syntax}
+Expands the \meta{tokens} exhaustively and returns the result.
+\end{function}
+
+\begin{function}{\ExpNot}
+\begin{syntax}
+\cs{ExpNot} \Arg{tokens}
+\end{syntax}
+Prevents expansion of the \meta{tokens} inside the argument of \cs{Expand} function.
+The argument of \cs{ExpNot} \emph{must} be surrounded by braces.
+%\begin{texnote}
+%This is the \eTeX{} \tn{unexpanded} primitive. In an
+%|x|-expanding definition (\cs{cs_new:Npx}), \cs{exp_not:n}~|{#1}|
+%is equivalent to |##1| rather than to~|#1|, namely it inserts the
+%two characters |#| and~|1|. In an |e|-type argument
+%\cs{exp_not:n}~|{#}| is equivalent to |#|, namely it inserts the
+%character~|#|.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\ExpValue}
+\begin{syntax}
+\cs{ExpValue} \meta{variable}
+\end{syntax}
+Recovers the content of the \meta{variable}, then prevents expansion
+of this material inside the argument of \cs{Expand} function.
+\end{function}
+
+\begin{function}{\UseOne,\GobbleOne}
+\begin{syntax}
+\cs{UseOne} \Arg{argument}
+\cs{GobbleOne} \Arg{argument}
+\end{syntax}
+The function \cs{UseOne} absorbs one argument and returns it.
+%\begin{texnote}
+%The \cs{UseOne} function is equivalent to \LaTeXe{}'s \tn{@firstofone}.
+%\end{texnote}
+\cs{GobbleOne} absorbs one argument and returns nothing.
+%\begin{texnote}
+%These are equivalent to \LaTeXe{}'s \tn{@gobble}, \tn{@gobbbletwo},
+%\emph{etc.}
+%\end{texnote}
+For example
+\begin{demohigh}
+\UseOne{abc}\GobbleOne{ijk}\UseOne{xyz}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\UseGobble,\GobbleUse}
+\begin{syntax}
+\cs{UseGobble} \Arg{arg_1} \Arg{arg_2}
+\cs{GobbleUse} \Arg{arg_1} \Arg{arg_2}
+\end{syntax}
+These functions absorb two arguments.
+The function \cs{UseGobble} discards the second argument,
+and returns the content of the first argument.
+\cs{GobbleUse} discards the first argument,
+and returns the content of the second argument.
+%\begin{texnote}
+%These are equivalent to \LaTeXe{}'s \tn{@firstoftwo} and
+%\tn{@secondoftwo}.
+%\end{texnote}
+For example
+\begin{demohigh}
+\UseGobble{abc}{uvw}\GobbleUse{abc}{uvw}
+\end{demohigh}
+\end{function}
+
+\chapter{Control Structures (\texttt{l3prg})}
+
+\section{Scratch Variables of Booleans}
+
+\begin{variable}{\lTmpaBool,\lTmpbBool,\lTmpcBool,\lTmpiBool,\lTmpjBool,\lTmpkBool}
+Scratch booleans for local assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\begin{variable}{\gTmpaBool,\gTmpbBool,\gTmpcBool,\gTmpiBool,\gTmpjBool,\gTmpkBool}
+Scratch booleans for global assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+%\BoolIfTF\cTrueBool{\Result{true}}{\Result{false}}
+%\BoolIfTF\cFalseBool{\Result{true}}{\Result{false}}
+
+\section{Public Functions for Booleans}
+
+\begin{function}{\BoolNew}
+\begin{syntax}
+\cs{BoolNew} \meta{boolean}
+\end{syntax}
+Creates a new \meta{boolean} or raises an error if the
+name is already taken. The declaration is global. The
+\meta{boolean} is initially \texttt{false}.
+\end{function}
+
+\begin{function}{\BoolSetTrue}
+\begin{syntax}
+\cs{BoolSetTrue} \meta{boolean}
+\end{syntax}
+Sets \meta{boolean} logically \texttt{true}.
+\end{function}
+
+\begin{function}{\BoolSetFalse}
+\begin{syntax}
+\cs{BoolSetFalse} \meta{boolean}
+\end{syntax}
+Sets \meta{boolean} logically \texttt{false}.
+\end{function}
+
+\begin{function}{\BoolIf,\BoolIfTF}
+\begin{syntax}
+\cs{BoolIf} \meta{boolean}
+\cs{BoolIfTF} \meta{boolean} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests the current truth of \meta{boolean}, and continues evaluation
+based on this result. For example
+\begin{demohigh}
+\BoolSetTrue\lTmpaBool
+\BoolIfTF\lTmpaBool{\Result{True!}}{\Result{False!}}
+\BoolSetFalse\lTmpaBool
+\BoolIfTF\lTmpaBool{\Result{True!}}{\Result{False!}}
+\end{demohigh}
+\end{function}
+
+\chapter{Token Lists (\texttt{l3tl})}
+
+\section{Scratch Variables of Token Lists}
+
+\begin{variable}{\lTmpaTl,\lTmpbTl,\lTmpcTl,\lTmpiTl,\lTmpjTl,\lTmpkTl}
+Scratch token lists for local assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\begin{variable}{\gTmpaTl,\gTmpbTl,\gTmpcTl,\gTmpiTl,\gTmpjTl,\gTmpkTl}
+Scratch token lists for global assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\section{Public Functions for Token Lists}
+
+\begin{function}{\TlNew}
+\begin{syntax}
+\cs{TlNew} \meta{tl~var}
+\end{syntax}
+Creates a new \meta{tl~var} or raises an error if the
+name is already taken. The declaration is global. The
+\meta{tl~var} is initially empty.
+\end{function}
+
+\begin{function}{\TlUse}
+\begin{syntax}
+\cs{TlUse} \meta{tl~var}
+\end{syntax}
+Recovers the content of a \meta{tl~var} and returns the value.
+An error is raised if the variable
+does not exist or if it is invalid. Note that it is possible to use
+a \meta{tl~var} directly without an accessor function.
+\end{function}
+
+\begin{function}{\TlSet}
+\begin{syntax}
+\cs{TlSet} \meta{tl~var} \Arg{tokens}
+\end{syntax}
+Sets \meta{tl~var} to contain \meta{tokens},
+removing any previous content from the variable. For example
+\begin{demohigh}
+\TlSet\lTmpiTl{\IntMathMult{4}{5}}
+\TlUse\lTmpiTl
+\end{demohigh}
+\end{function}
+
+\begin{function}{\TlClear}
+\begin{syntax}
+\cs{TlClear} \meta{tl~var}
+\end{syntax}
+Clears all entries from the \meta{tl~var}. For example
+\begin{demohigh}
+\TlSet\lTmpjTl{One}
+\TlClear\lTmpjTl
+\TlSet\lTmpjTl{Two}
+\TlUse\lTmpjTl
+\end{demohigh}
+\end{function}
+
+\begin{function}{\TlPutLeft}
+\begin{syntax}
+\cs{TlPutLeft} \meta{tl~var} \Arg{tokens}
+\end{syntax}
+Appends \meta{tokens} to the left side of the current content of
+\meta{tl~var}. For example
+\begin{demohigh}
+\TlSet\lTmpkTl{Functional}
+\TlPutLeft\lTmpkTl{Hello}
+\TlUse\lTmpkTl
+\end{demohigh}
+\end{function}
+
+\begin{function}{\TlPutRight}
+\begin{syntax}
+\cs{TlPutRight} \meta{tl~var} \Arg{tokens}
+\end{syntax}
+Appends \meta{tokens} to the right side of the current content of
+\meta{tl~var}. For example
+\begin{demohigh}
+\TlSet\lTmpkTl{Functional}
+\TlPutRight\lTmpkTl{World}
+\TlUse\lTmpkTl
+\end{demohigh}
+\end{function}
+
+\begin{function}{\TlIfEmpty,\TlIfEmptyTF}
+\begin{syntax}
+\cs{TlIfEmpty} \meta{tl~var}
+\cs{TlIfEmptyTF} \meta{tl~var} \Arg{true code} \Arg{false code}
+\end{syntax}
+Tests if the \meta{token list variable} is entirely empty
+(\emph{i.e.}~contains no tokens at all). For example
+\begin{demohigh}
+\TlSet\lTmpaTl{abc}
+\TlIfEmptyTF\lTmpaTl{\Result{Empty}}{\Result{NonEmpty}}
+\TlClear\lTmpaTl
+\TlIfEmptyTF\lTmpaTl{\Result{Empty}}{\Result{NonEmpty}}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\TlIfEq,\TlIfEqTF}
+\begin{syntax}
+\cs{TlIfEq} \meta{tl~var_1} \meta{tl~var_2}
+\cs{TlIfEqTF} \meta{tl~var_1} \meta{tl~var_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+Compares the content of two \meta{token list variables} and
+is logically \texttt{true} if the two contain the same list of
+tokens (\emph{i.e.}~identical in both the list of characters they
+contain and the category codes of those characters). For example
+\begin{demohigh}
+\TlSet\lTmpaTl{abc}
+\TlSet\lTmpbTl{abc}
+\TlSet\lTmpcTl{xyz}
+\TlIfEqTF\lTmpaTl\lTmpbTl{\Result{Yes}}{\Result{No}}
+\TlIfEqTF\lTmpaTl\lTmpcTl{\Result{Yes}}{\Result{No}}
+\end{demohigh}
+%See also \cs{StrIfEqTF} for a comparison that ignores category codes.
+\end{function}
+
+\chapter{Integers (\texttt{l3int})}
+
+\section{Scratch Variables of Integers}
+
+\begin{variable}{\lTmpaInt,\lTmpbInt,\lTmpcInt,\lTmpiInt,\lTmpjInt,\lTmpkInt}
+Scratch integer for local assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\begin{variable}{\gTmpaInt,\gTmpbInt,\gTmpcInt,\gTmpiInt,\gTmpjInt,\gTmpkInt}
+Scratch integer for global assignment. These are never used by
+the \verb!functional! package, and so are safe for use with any
+function. However, they may be overwritten by other
+code and so should only be used for short-term storage.
+\end{variable}
+
+\section{Public Functions for Integers}
+
+\begin{function}{\IntEval}
+\begin{syntax}
+\cs{IntEval} \Arg{integer expression}
+\end{syntax}
+Evaluates the \meta{integer expression} and returns the result:
+for positive results an
+explicit sequence of decimal digits not starting with~\texttt{0},
+for negative results \texttt{-}~followed by such a sequence, and
+\texttt{0}~for zero. For example
+\begin{demohigh}
+\IntEval{(1+4)*(2-3)/5}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntMathAdd}
+\begin{syntax}
+\cs{IntMathAdd} \Arg{integer expression_1} \Arg{integer expression_2}
+\end{syntax}
+Adds \Arg{integer expression_1} and \Arg{integer expression_2},
+and returns the result. For example
+\begin{demohigh}
+\IntMathAdd{7}{3}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntMathSub}
+\begin{syntax}
+\cs{IntMathSub} \Arg{integer expression_1} \Arg{integer expression_2}
+\end{syntax}
+Subtracts \Arg{integer expression_1} from \Arg{integer expression_2},
+and returns the result. For example
+\begin{demohigh}
+\IntMathSub{7}{3}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntMathMult}
+\begin{syntax}
+\cs{IntMathMult} \Arg{integer expression_1} \Arg{integer expression_2}
+\end{syntax}
+Multiplies \Arg{integer expression_1} by \Arg{integer expression_2},
+and returns the result. For example
+\begin{demohigh}
+\IntMathMult{7}{3}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntMathDiv}
+\begin{syntax}
+\cs{IntMathDiv} \Arg{integer expression_1} \Arg{integer expression_2}
+\end{syntax}
+Divides \Arg{integer expression_1} by \Arg{integer expression_2},
+and returns the result. For example
+\begin{demohigh}
+\IntMathDiv{7}{3}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntNew}
+\begin{syntax}
+\cs{IntNew} \meta{integer}
+\end{syntax}
+Creates a new \meta{integer} or raises an error if the name is
+already taken. The declaration is global. The \meta{integer} is
+initially equal to $0$.
+\end{function}
+
+\begin{function}{\IntUse}
+\begin{syntax}
+\cs{IntUse} \meta{integer}
+\end{syntax}
+Recovers the content of an \meta{integer} and returns the value.
+An error is raised if the variable does
+not exist or if it is invalid. Can be omitted in places where an
+\meta{integer} is required (such as in the first and third arguments
+of \cs{IntCompareTF}).%
+%\begin{texnote}
+%\cs{IntUse} is the \TeX{} primitive \tn{the}: this is one of
+%several \verb!functional! names for this primitive.
+%\end{texnote}
+\end{function}
+
+\begin{function}{\IntSet}
+\begin{syntax}
+\cs{IntSet} \meta{integer} \Arg{integer expression}
+\end{syntax}
+Sets \meta{integer} to the value of \meta{integer expression},
+which must evaluate to an integer (as described for \cs{IntEval}).
+For example
+\begin{demohigh}
+\IntSet\lTmpaInt{3+5}
+\IntUse\lTmpaInt
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntZero}
+\begin{syntax}
+\cs{IntZero} \meta{integer}
+\end{syntax}
+Sets \meta{integer} to $0$. For example
+\begin{demohigh}
+\IntSet\lTmpaInt{5}
+\IntZero\lTmpaInt
+\IntUse\lTmpaInt
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntIncr}
+\begin{syntax}
+\cs{IntIncr} \meta{integer}
+\end{syntax}
+Increases the value stored in \meta{integer} by $1$.
+For example
+\begin{demohigh}
+\IntSet\lTmpaInt{5}
+\IntIncr\lTmpaInt
+\IntUse\lTmpaInt
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntDecr}
+\begin{syntax}
+\cs{IntDecr} \meta{integer}
+\end{syntax}
+Decreases the value stored in \meta{integer} by $1$.
+For example
+\begin{demohigh}
+\IntSet\lTmpaInt{5}
+\IntDecr\lTmpaInt
+\IntUse\lTmpaInt
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntAdd}
+\begin{syntax}
+\cs{IntAdd} \meta{integer} \Arg{integer expression}
+\end{syntax}
+Adds the result of the \meta{integer expression} to the current
+content of the \meta{integer}. For example
+\begin{demohigh}
+\IntSet\lTmpaInt{5}
+\IntAdd\lTmpaInt{2}
+\IntUse\lTmpaInt
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntSub}
+\begin{syntax}
+\cs{IntSub} \meta{integer} \Arg{integer expression}
+\end{syntax}
+Subtracts the result of the \meta{integer expression} from the
+current content of the \meta{integer}. For example
+\begin{demohigh}
+\IntSet\lTmpaInt{5}
+\IntSub\lTmpaInt{3}
+\IntUse\lTmpaInt
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntStepVariable}
+\begin{syntax}
+\cs{IntStepVariable} \Arg{initial value} \Arg{step} \Arg{final value} \meta{tl~var} \Arg{code}
+\end{syntax}
+This function first evaluates the \meta{initial value}, \meta{step}
+and \meta{final value}, all of which should be integer expressions.
+Then for each \meta{value} from the \meta{initial value} to the
+\meta{final value} in turn (using \meta{step} between each
+\meta{value}), the \meta{code} is evaluated,
+with the \meta{tl~var} defined as the current \meta{value}. Thus
+the \meta{code} should make use of the \meta{tl~var}.
+For example
+\begin{demohigh}
+\TlClear\lTmpaTl
+\IntStepVariable{1}{3}{30}\lTmpiTl{
+ \TlPutRight\lTmpaTl{\Value\lTmpiTl}
+ \TlPutRight\lTmpaTl{ }
+}
+\Result{\Value\lTmpaTl}
+\end{demohigh}
+\end{function}
+
+\begin{function}{\IntCompare,\IntCompareTF}
+\begin{syntax}
+\cs{IntCompare} \Arg{intexpr_1} \meta{relation} \Arg{intexpr_2}
+\cs{IntCompareTF} \Arg{intexpr_1} \meta{relation} \Arg{intexpr_2} \Arg{true code} \Arg{false code}
+\end{syntax}
+This function first evaluates each of the \meta{integer expressions}
+as described for \cs{IntEval}. The two results are then
+compared using the \meta{relation}:\par
+{\centering\begin{tabular}{ll}
+Equal & \texttt{=} \\
+Greater than & \texttt{>} \\
+Less than & \texttt{<} \\
+\end{tabular}\par}
+For example
+\begin{demohigh}
+\IntCompareTF{2}>{1}{\Result{Greater}}{\Result{Less}}
+\IntCompareTF{2}>{3}{\Result{Greater}}{\Result{Less}}
+\end{demohigh}
+\end{function}
+
+\chapter{The Source Code}
+
+%\CodeHigh{lite}
+\setlength\parskip{0pt}
+\dochighinput[language=latex/latex3]{functional.sty}
+
+\end{document}
+
diff --git a/Master/texmf-dist/tex/latex/functional/functional.sty b/Master/texmf-dist/tex/latex/functional/functional.sty
new file mode 100644
index 00000000000..95e5ada3dc2
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/functional/functional.sty
@@ -0,0 +1,686 @@
+%%% -*- coding: utf-8 -*-
+%% ----------------------------------------------------------------------------
+%% Functional: LaTeX2 functional interfaces to LaTeX3 programming layer
+%% Copyright : 2022 (c) Jianrui Lyu <tolvjr@163.com>
+%% Repository: https://github.com/lvjr/functional
+%% License : The LaTeX Project Public License 1.3c
+%% ----------------------------------------------------------------------------
+
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Function Definitions (l3basics)}
+%%% --------------------------------------------------------
+
+\NeedsTeXFormat{LaTeX2e}[2018-04-01]
+
+\RequirePackage{expl3}
+\ProvidesExplPackage{functional}{2022-03-10}{2022A}
+ {^^JLaTeX2 functional interfaces to LaTeX3 programming layer}
+
+\cs_generate_variant:Nn \iow_log:n { V }
+\cs_generate_variant:Nn \tl_set:Nn { Ne }
+
+\tl_new:N \gResultTl
+\int_new:N \l__fun_arg_count_int
+\tl_new:N \l__fun_parameters_defined_tl
+\tl_const:Nn \c__fun_parameter_defined_i__tl { } % no argument
+\tl_const:Nn \c__fun_parameter_defined_i_i_tl { #1 }
+\tl_const:Nn \c__fun_parameter_defined_i_ii_tl { #1 #2 }
+\tl_const:Nn \c__fun_parameter_defined_i_iii_tl { #1 #2 #3 }
+\tl_const:Nn \c__fun_parameter_defined_i_iv_tl { #1 #2 #3 #4 }
+\tl_const:Nn \c__fun_parameter_defined_i_v_tl { #1 #2 #3 #4 #5 }
+\tl_const:Nn \c__fun_parameter_defined_i_vi_tl { #1 #2 #3 #4 #5 #6 }
+\tl_const:Nn \c__fun_parameter_defined_i_vii_tl { #1 #2 #3 #4 #5 #6 #7 }
+\tl_const:Nn \c__fun_parameter_defined_i_viii_tl { #1 #2 #3 #4 #5 #6 #7 #8 }
+\tl_const:Nn \c__fun_parameter_defined_i_ix_tl { #1 #2 #3 #4 #5 #6 #7 #8 #9 }
+\tl_new:N \l__fun_parameters_called_tl
+\tl_const:Nn \c__fun_parameter_called_i_i_tl { {#1} }
+\tl_const:Nn \c__fun_parameter_called_i_ii_tl { {#1}{#2} }
+\tl_const:Nn \c__fun_parameter_called_i_iii_tl { {#1}{#2}{#3} }
+\tl_const:Nn \c__fun_parameter_called_i_iv_tl { {#1}{#2}{#3}{#4} }
+\tl_const:Nn \c__fun_parameter_called_i_v_tl { {#1}{#2}{#3}{#4}{#5} }
+\tl_const:Nn \c__fun_parameter_called_i_vi_tl { {#1}{#2}{#3}{#4}{#5}{#6} }
+\tl_const:Nn \c__fun_parameter_called_i_vii_tl { {#1}{#2}{#3}{#4}{#5}{#6}{#7} }
+\tl_new:N \l__fun_parameters_true_tl
+\tl_new:N \l__fun_parameters_false_tl
+\tl_const:Nn \c__fun_parameter_called_i_tl { {#1} }
+\tl_const:Nn \c__fun_parameter_called_ii_tl { {#2} }
+\tl_const:Nn \c__fun_parameter_called_iii_tl { {#3} }
+\tl_const:Nn \c__fun_parameter_called_iv_tl { {#4} }
+\tl_const:Nn \c__fun_parameter_called_v_tl { {#5} }
+\tl_const:Nn \c__fun_parameter_called_vi_tl { {#6} }
+\tl_const:Nn \c__fun_parameter_called_vii_tl { {#7} }
+\tl_const:Nn \c__fun_parameter_called_viii_tl { {#8} }
+\tl_const:Nn \c__fun_parameter_called_ix_tl { {#9} }
+\tl_new:N \l__fun_argument_tl
+\tl_new:N \l__fun_argument_i_tl
+\tl_new:N \l__fun_argument_ii_tl
+\tl_new:N \l__fun_argument_iii_tl
+\tl_new:N \l__fun_argument_iv_tl
+\tl_new:N \l__fun_argument_v_tl
+\tl_new:N \l__fun_argument_vi_tl
+\tl_new:N \l__fun_argument_vii_tl
+\tl_new:N \l__fun_argument_viii_tl
+\tl_new:N \l__fun_argument_ix_tl
+
+%% #1: function name; #2: argument specification; #3 function body
+\cs_new_protected:Npn \__fun_new_function:Nnn #1 #2 #3
+ {
+ \int_set:Nn \l__fun_arg_count_int { \tl_count:n {#2} } % spaces are ignored
+ \tl_set_eq:Nc \l__fun_parameters_defined_tl
+ { c__fun_parameter_defined_i_ \int_to_roman:n { \l__fun_arg_count_int } _tl }
+ \exp_last_unbraced:NcV \cs_new_protected:Npn
+ { __fun_defined_ \cs_to_str:N #1 : w }
+ \l__fun_parameters_defined_tl
+ {
+ \__fun_group_begin:
+ \tl_gclear:N \gResultTl
+ #3
+ \__fun_tracing_log:e { [O] ~ \gResultTl }
+ \__fun_group_end:
+ }
+ \use:c { __fun_new_with_arg_ \int_to_roman:n { \l__fun_arg_count_int } :NnV }
+ #1 {#2} \l__fun_parameters_defined_tl
+ }
+\cs_generate_variant:Nn \__fun_new_function:Nnn { cne }
+
+\cs_set_eq:NN \PrgNewFunction \__fun_new_function:Nnn
+
+\tl_new:N \g__fun_last_result_tl
+
+%% #1: function name; #2: argument specification; #3 function body
+\cs_new_protected:Npn \__fun_new_conditional:Nnn #1 #2 #3
+ {
+ \__fun_new_function:Nnn #1 { #2 } { #3 }
+ \tl_set_eq:Nc \l__fun_parameters_called_tl
+ { c__fun_parameter_called_i_ \int_to_roman:n { \l__fun_arg_count_int } _tl }
+ \tl_set_eq:Nc \l__fun_parameters_true_tl
+ { c__fun_parameter_called_ \int_to_roman:n { \l__fun_arg_count_int + 1 } _tl }
+ \tl_set_eq:Nc \l__fun_parameters_false_tl
+ { c__fun_parameter_called_ \int_to_roman:n { \l__fun_arg_count_int + 2 } _tl }
+ \__fun_new_function:cne { \cs_to_str:N #1 TF } { #2 n n }
+ {
+ #1 \exp_not:V \l__fun_parameters_called_tl
+ \exp_not:n
+ {
+ \tl_set_eq:NN \g__fun_last_result_tl \gResultTl
+ \tl_gclear:N \gResultTl
+ \exp_last_unbraced:NV \bool_if:NTF \g__fun_last_result_tl
+ }
+ \exp_not:V \l__fun_parameters_true_tl
+ \exp_not:V \l__fun_parameters_false_tl
+ }
+ }
+
+\cs_set_eq:NN \PrgNewConditional \__fun_new_conditional:Nnn
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+%% Some times we need to create a function without arguments
+\cs_new_protected:Npn \__fun_new_with_arg_:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_i:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_i:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_ii:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_ii:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_iii:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_iii:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_iv:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
+ \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_iv:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_v:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
+ \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
+ \tl_set:Nn \l__fun_argument_v_tl { ##5 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_v:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_vi:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
+ \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
+ \tl_set:Nn \l__fun_argument_v_tl { ##5 }
+ \tl_set:Nn \l__fun_argument_vi_tl { ##6 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_vi:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_vii:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
+ \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
+ \tl_set:Nn \l__fun_argument_v_tl { ##5 }
+ \tl_set:Nn \l__fun_argument_vi_tl { ##6 }
+ \tl_set:Nn \l__fun_argument_vii_tl { ##7 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_vii:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_viii:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
+ \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
+ \tl_set:Nn \l__fun_argument_v_tl { ##5 }
+ \tl_set:Nn \l__fun_argument_vi_tl { ##6 }
+ \tl_set:Nn \l__fun_argument_vii_tl { ##7 }
+ \tl_set:Nn \l__fun_argument_viii_tl { ##8 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_viii:Nnn { NnV }
+
+%% #1: function name; #2: argument specifications; #3 parameters tl defined
+\cs_new_protected:Npn \__fun_new_with_arg_ix:Nnn #1 #2 #3
+ {
+ \cs_new_protected:Npn #1 #3
+ {
+ \tl_set:Nn \l__fun_argument_i_tl { ##1 }
+ \tl_set:Nn \l__fun_argument_ii_tl { ##2 }
+ \tl_set:Nn \l__fun_argument_iii_tl { ##3 }
+ \tl_set:Nn \l__fun_argument_iv_tl { ##4 }
+ \tl_set:Nn \l__fun_argument_v_tl { ##5 }
+ \tl_set:Nn \l__fun_argument_vi_tl { ##6 }
+ \tl_set:Nn \l__fun_argument_vii_tl { ##7 }
+ \tl_set:Nn \l__fun_argument_viii_tl { ##8 }
+ \tl_set:Nn \l__fun_argument_ix_tl { ##9 }
+ \__fun_evaluate:Nn #1 {#2}
+ }
+ }
+\cs_generate_variant:Nn \__fun_new_with_arg_ix:Nnn { NnV }
+
+\int_new:N \g__fun_nesting_level_int
+\int_new:N \l__fun_argtype_number_int
+\tl_new:N \l__fun_argtype_tl
+\tl_const:Nn \c__fun_argtype_m_tl { m }
+\tl_const:Nn \c__fun_argtype_M_tl { M }
+\tl_const:Nn \c__fun_argtype_n_tl { n }
+\tl_const:Nn \c__fun_argtype_N_tl { N }
+
+%% #1: function name; #2: argument specifications
+\cs_new_protected:Npn \__fun_evaluate:Nn #1 #2
+ {
+ \int_zero:N \l__fun_argtype_number_int
+ \int_gincr:N \g__fun_nesting_level_int
+ \__fun_arguments_gclear:
+ \tl_map_variable:nNn { #2 } \l__fun_argtype_tl % spaces are ignored
+ {
+ \int_incr:N \l__fun_argtype_number_int
+ \tl_set_eq:Nc \l__fun_argument_tl
+ { l__fun_argument_ \int_to_roman:n { \l__fun_argtype_number_int } _tl }
+ \tl_case:Nn \l__fun_argtype_tl
+ {
+ \c__fun_argtype_m_tl
+ {
+ \__fun_evaluate_and_put_argument:N \l__fun_argument_tl
+ }
+ \c__fun_argtype_M_tl
+ {
+ \__fun_evaluate_and_put_argument:N \l__fun_argument_tl
+ }
+ \c__fun_argtype_n_tl
+ {
+ \__fun_arguments_gput:e { { \exp_not:V \l__fun_argument_tl } }
+ }
+ \c__fun_argtype_N_tl
+ {
+ \__fun_arguments_gput:e { \exp_not:V \l__fun_argument_tl }
+ }
+ }
+ }
+ \__fun_arguments_log:N #1
+ \__fun_arguments_called:c { __fun_defined_ \cs_to_str:N #1 : w }
+ \int_gdecr:N \g__fun_nesting_level_int
+ \__fun_return_result:
+ }
+
+\cs_set_eq:NN \__fun_cs_temp:w \scan_stop:
+
+\cs_new_protected:Npn \__fun_evaluate_and_put_argument:N #1
+ {
+ \cs_set_eq:Nc \__fun_cs_temp:w
+ {
+ __fun_defined_ \exp_last_unbraced:Ne \cs_to_str:N { \tl_head:N #1 } : w
+ }
+ \cs_if_exist:NTF \__fun_cs_temp:w
+ {
+ #1
+ \__fun_arguments_gput:e { { \exp_not:V \gResultTl } }
+ }
+ {
+ \__fun_arguments_gput:e { { \exp_not:V #1 } }
+ }
+ }
+
+\cs_new_protected:Npn \__fun_arguments_called:N #1
+ {
+ \exp_last_unbraced:Nv
+ #1 { g__fun_arguments_ \int_use:N \g__fun_nesting_level_int _tl }
+ }
+\cs_generate_variant:Nn \__fun_arguments_called:N { c }
+
+\cs_new_protected:Npn \__fun_arguments_gclear:
+ {
+ \tl_gclear:c { g__fun_arguments_ \int_use:N \g__fun_nesting_level_int _tl }
+ }
+
+\cs_new_protected:Npn \__fun_arguments_log:N #1
+ {
+ \__fun_tracing_log:e
+ {
+ [I] ~ \token_to_str:N #1
+ \exp_not:v { g__fun_arguments_ \int_use:N \g__fun_nesting_level_int _tl }
+ }
+ }
+
+\cs_new_protected:Npn \__fun_arguments_gput:n #1
+ {
+ \tl_gput_right:cn
+ { g__fun_arguments_ \int_use:N \g__fun_nesting_level_int _tl } { #1 }
+ }
+\cs_generate_variant:Nn \__fun_arguments_gput:n { e }
+
+\cs_new_protected:Npn \__fun_put_result:n #1
+ {
+ \tl_gput_right:Nn \gResultTl { #1 }
+ }
+\cs_generate_variant:Nn \__fun_put_result:n { e, V }
+
+\PrgNewFunction \Result { m }
+ {
+ \__fun_put_result:n { #1 }
+ }
+
+\PrgNewFunction \Name { m }
+ {
+ \exp_args:Nc \__fun_put_result:n { #1 }
+ }
+\cs_set_eq:NN \UseName \Name
+
+\PrgNewFunction \Expand { m }
+ {
+ \__fun_put_result:e { #1 }
+ }
+\cs_set_eq:NN \UseExpand \Expand
+
+\PrgNewFunction \Value { M }
+ {
+ \__fun_put_result:V #1
+ }
+\cs_set_eq:NN \UseValue \Value
+
+\cs_set_eq:NN \ExpNot \exp_not:n
+\cs_set_eq:NN \ExpValue \exp_not:V
+
+\cs_new_protected:Npn \__fun_return_result:
+ {
+ \int_compare:nNnT { \g__fun_nesting_level_int } = { 0 }
+ { \tl_use:N \gResultTl }
+ }
+
+\tl_new:N \l__fun_variable_type_tl
+
+\prg_new_protected_conditional:Npnn \__fun_if_global_variable:N #1 { TF }
+ {
+ \tl_set:Ne \l__fun_variable_type_tl
+ { \exp_args:Ne \tl_head:n { \cs_to_str:N #1 } }
+ \str_if_eq:VnTF \l__fun_variable_type_tl { g }
+ { \prg_return_true: }
+ {
+ \str_if_eq:VnTF \l__fun_variable_type_tl { c }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+
+%% We must not put an assignment inside a group
+\cs_new_protected:Npn \__fun_do_assignment:Nnn #1 #2 #3
+ {
+ \__fun_group_end:
+ \__fun_if_global_variable:NTF #1 { #2 } { #3 }
+ \__fun_group_begin:
+ }
+
+\bool_new:N \l__fun_scoping_bool
+
+\cs_new_protected:Npn \__fun_scoping_true:
+ {
+ \cs_set_eq:NN \__fun_group_begin: \group_begin:
+ \cs_set_eq:NN \__fun_group_end: \group_end:
+ }
+
+\cs_new_protected:Npn \__fun_scoping_false:
+ {
+ \cs_set_eq:NN \__fun_group_begin: \scan_stop:
+ \cs_set_eq:NN \__fun_group_end: \scan_stop:
+ }
+
+\cs_new_protected:Npn \__fun_scoping_set:
+ {
+ \bool_if:NTF \l__fun_scoping_bool
+ { \__fun_scoping_true: } { \__fun_scoping_false: }
+ }
+
+\bool_new:N \l__fun_tracing_bool
+\tl_new:N \l__tracing_text_tl
+
+\cs_new_protected:Npn \__fun_tracing_log_on:n #1
+ {
+ \tl_set:Ne \l__tracing_text_tl
+ {
+ \prg_replicate:nn
+ { \int_eval:n { (\g__fun_nesting_level_int - 1) * 4 } } { ~ }
+ }
+ \tl_put_right:Nn \l__tracing_text_tl { #1 }
+ \iow_log:V \l__tracing_text_tl
+ }
+\cs_generate_variant:Nn \__fun_tracing_log_on:n { e, V }
+
+\cs_new_protected:Npn \__fun_tracing_log_off:n #1 { }
+\cs_generate_variant:Nn \__fun_tracing_log_off:n { e, V }
+
+\cs_new_protected:Npn \__fun_tracing_true:
+ {
+ \cs_set_eq:NN \__fun_tracing_log:n \__fun_tracing_log_on:n
+ \cs_set_eq:NN \__fun_tracing_log:e \__fun_tracing_log_on:e
+ \cs_set_eq:NN \__fun_tracing_log:V \__fun_tracing_log_on:V
+ }
+
+\cs_new_protected:Npn \__fun_tracing_false:
+ {
+ \cs_set_eq:NN \__fun_tracing_log:n \__fun_tracing_log_off:n
+ \cs_set_eq:NN \__fun_tracing_log:e \__fun_tracing_log_off:e
+ \cs_set_eq:NN \__fun_tracing_log:V \__fun_tracing_log_off:V
+ }
+
+\cs_new_protected:Npn \__fun_tracing_set:
+ {
+ \bool_if:NTF \l__fun_tracing_bool
+ { \__fun_tracing_true: } { \__fun_tracing_false: }
+ }
+
+\keys_define:nn { functional }
+ {
+ scoping .bool_set:N = \l__fun_scoping_bool,
+ tracing .bool_set:N = \l__fun_tracing_bool,
+ }
+
+\NewDocumentCommand \Functional { m }
+ {
+ \keys_set:nn { functional } { #1 }
+ \__fun_scoping_set:
+ \__fun_tracing_set:
+ }
+
+\Functional { scoping = false, tracing = false }
+
+\PrgNewFunction \UseOne { n }
+ {
+ \Result { #1 }
+ }
+
+\PrgNewFunction \GobbleOne { n }
+ {
+ \Result { }
+ }
+
+\PrgNewFunction \UseGobble { n n }
+ {
+ \UseOne { #1 }
+ }
+
+\PrgNewFunction \GobbleUse { n n }
+ {
+ \UseOne { #2 }
+ }
+
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Control Structures (l3prg)}
+%%% --------------------------------------------------------
+
+\bool_const:Nn \cTrueBool { \c_true_bool }
+\bool_const:Nn \cFalseBool { \c_false_bool }
+
+\bool_new:N \lTmpaBool \bool_new:N \lTmpbBool \bool_new:N \lTmpcBool
+\bool_new:N \lTmpiBool \bool_new:N \lTmpjBool \bool_new:N \lTmpkBool
+\bool_new:N \l@Funx@Bool \bool_new:N \l@Funy@Bool \bool_new:N \l@Funz@Bool
+
+\bool_new:N \gTmpaBool \bool_new:N \gTmpbBool \bool_new:N \gTmpcBool
+\bool_new:N \gTmpiBool \bool_new:N \gTmpjBool \bool_new:N \gTmpkBool
+\bool_new:N \g@Funx@Bool \bool_new:N \g@Funy@Bool \bool_new:N \g@Funz@Bool
+
+\cs_set_eq:NN \BoolNew \bool_new:N
+\cs_set_eq:NN \BoolLog \bool_log:N
+
+\PrgNewFunction \BoolSetTrue { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \bool_gset_true:N #1 } { \bool_set_true:N #1 }
+ }
+
+\PrgNewFunction \BoolSetFalse { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \bool_gset_false:N #1 } { \bool_set_false:N #1 }
+ }
+
+\PrgNewConditional \BoolIf { N }
+ {
+ \Result { #1 }
+ }
+
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Token Lists (l3tl)}
+%%% --------------------------------------------------------
+
+\tl_new:N \lTmpaTl \tl_new:N \lTmpbTl \tl_new:N \lTmpcTl
+\tl_new:N \lTmpiTl \tl_new:N \lTmpjTl \tl_new:N \lTmpkTl
+\tl_new:N \l@Funx@Tl \tl_new:N \l@Funy@Tl \tl_new:N \l@Funz@Tl
+
+\tl_new:N \gTmpaTl \tl_new:N \gTmpbTl \tl_new:N \gTmpcTl
+\tl_new:N \gTmpiTl \tl_new:N \gTmpjTl \tl_new:N \gTmpkTl
+\tl_new:N \g@Funx@Tl \tl_new:N \g@Funy@Tl \tl_new:N \g@Funz@Tl
+
+\cs_set_eq:NN \TlNew \tl_new:N
+\cs_set_eq:NN \TlLog \tl_log:N
+
+\PrgNewFunction \TlClear { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \tl_gclear:N #1 } { \tl_clear:N #1 }
+ }
+
+\PrgNewFunction \TlSet { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \tl_gset:Nn #1 {#2} } { \tl_set:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \TlPutLeft { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \tl_gput_left:Nn #1 {#2} } { \tl_put_left:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \TlPutRight { M m }
+ {
+ \__fun_do_assignment:Nnn #1
+ { \tl_gput_right:Nn #1 {#2} } { \tl_put_right:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \TlUse { M }
+ {
+ \Result { \Value #1 }
+ }
+
+\PrgNewConditional \TlIfEmpty { N }
+ {
+ \tl_if_empty:NTF #1
+ { \Result { \cTrueBool } }
+ { \Result { \cFalseBool } }
+ }
+
+\PrgNewConditional \TlIfEq { N N }
+ {
+ \tl_if_eq:NNTF #1 #2
+ { \Result { \cTrueBool } }
+ { \Result { \cFalseBool } }
+ }
+
+%%% --------------------------------------------------------
+%%> \section{Interfaces for Integers (l3int)}
+%%% --------------------------------------------------------
+
+\int_new:N \lTmpaInt \int_new:N \lTmpbInt \int_new:N \lTmpcInt
+\int_new:N \lTmpiInt \int_new:N \lTmpjInt \int_new:N \lTmpkInt
+\int_new:N \l@Funx@Int \int_new:N \l@Funy@Int \int_new:N \l@Funz@Int
+
+\int_new:N \gTmpaInt \int_new:N \gTmpbInt \int_new:N \gTmpcInt
+\int_new:N \gTmpiInt \int_new:N \gTmpjInt \int_new:N \gTmpkInt
+\int_new:N \g@Funx@Int \int_new:N \g@Funy@Int \int_new:N \g@Funz@Int
+
+\cs_set_eq:NN \IntNew \int_new:N
+\cs_set_eq:NN \IntLog \int_log:N
+
+\PrgNewFunction \IntZero { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gzero:N #1 } { \int_zero:N #1 }
+ }
+
+\PrgNewFunction \IntIncr { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gincr:N #1 } { \int_incr:N #1 }
+ }
+
+\PrgNewFunction \IntDecr { M }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gdecr:N #1 } { \int_decr:N #1 }
+ }
+
+\PrgNewFunction \IntSet { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gset:Nn #1 {#2} } { \int_set:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \IntAdd { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gadd:Nn #1 {#2} } { \int_add:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \IntSub { M m }
+ {
+ \__fun_do_assignment:Nnn #1 { \int_gsub:Nn #1 {#2} } { \int_sub:Nn #1 {#2} }
+ }
+
+\PrgNewFunction \IntUse { M }
+ {
+ \Result { \Value #1 }
+ }
+
+\PrgNewFunction \IntEval { m }
+ {
+ \Result { \Expand { \int_eval:n { #1 } } }
+ }
+
+\PrgNewFunction \IntMathAdd { m m }
+ {
+ \int_set:Nn \l@Funx@Int { \int_eval:n { #1 + #2 } }
+ \Result { \Value \l@Funx@Int }
+ }
+
+\PrgNewFunction \IntMathSub { m m }
+ {
+ \int_set:Nn \l@Funx@Int { \int_eval:n { #1 - #2 } }
+ \Result { \Value \l@Funx@Int }
+ }
+
+\PrgNewFunction \IntMathMult { m m }
+ {
+ \int_set:Nn \l@Funx@Int { \int_eval:n { #1 * #2 } }
+ \Result { \Value \l@Funx@Int }
+ }
+
+\PrgNewFunction \IntMathDiv { m m }
+ {
+ \int_set:Nn \l@Funx@Int { \int_eval:n { #1 / #2 } }
+ \Result { \Value \l@Funx@Int }
+ }
+
+\PrgNewFunction \IntStepVariable { m m m M n }
+ {
+ \int_step_variable:nnnNn { #1 } { #2 } { #3 } #4 { #5 }
+ }
+
+\PrgNewConditional \IntCompare { m N m }
+ {
+ \int_compare:nNnTF {#1} #2 {#3}
+ { \Result { \cTrueBool } }
+ { \Result { \cFalseBool } }
+ }
+
diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
index c96d738e892..b57f125366c 100644
--- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
@@ -543,6 +543,7 @@ depend ftnxtra
depend fullblck
depend fullminipage
depend fullwidth
+depend functional
depend fundus-calligra
depend fundus-cyr
depend fundus-sueterlin
diff --git a/Master/tlpkg/tlpsrc/functional.tlpsrc b/Master/tlpkg/tlpsrc/functional.tlpsrc
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/functional.tlpsrc