如果我没理解错的话,token 列表是全局声明的,但可以在本地赋值。因此,所有同名的局部变量实际上都是全局声明为同一个变量。函数经常需要使用局部变量,很难确保这些局部变量没有名称冲突。例如:
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\tl_new:N \l_module_my_tl
%% Example 1: A function group is wanted.
\cs_new:Npn \module_outer:
{
\tl_set:Nn \l_module_my_tl { outer }
\tl_show:N \l_module_my_tl
\module_inner:
\tl_show:N \l_module_my_tl
}
\cs_new:Npn \module_inner:
{{ %% If you change this to { you'd get wrong result.
\tl_show:N \l_module_my_tl
\tl_set:Nn \l_module_my_tl { inner }
\tl_show:N \l_module_my_tl
}} %% If you change this to } you'd get wrong result.
\module_outer:
%% Example 2: A function group is unwanted.
\cs_new:Npn \module_tokens:
{ %% If you change this to {{ you'd get wrong result.
{ 1 } { 2 } { 3 }
} %% If you change this to }} you'd get wrong result.
\tl_set:Nx \l_module_my_tl { \module_tokens: }
\tl_show:N \l_module_my_tl
\ExplSyntaxOff
\end{document}
在此代码的第一个示例中,外部函数和内部函数都使用相同的标记列表\l_module_my_tl
。不幸的是,内部函数中的更改会传播到外部函数,这是不受欢迎的。一个简单的解决方案是为内部函数添加一个函数级组。
但是如果函数有输出,这个函数级组可能会引起问题,如第二个示例所示。如果添加了函数级组,它会输出{{1}{2}{3}}
但不会{1}{2}{3}
。
什么是一个通用的解决方案(程序员可以遵循而不需要逐案关注的通用惯例)可以使这两个示例都能正常工作?
答案1
在许多编程语言中,例如Lua
,函数或条件表达式会构成一个块,并且局部变量的值将在块之后重置。例如
---- lua code ----
local tmp = "a"
print(tmp) ---- tmp=a
function SomeFun()
local tmp = "b"
print(tmp) ---- tmp=b
if 1 > 0 then
local tmp = "c"
print(tmp) ---- tmp=c
end
print(tmp) ---- tmp=b
end
SomeFun()
print(tmp) ---- tmp=a
最近我写道functional
基于 的包expl3
。在这个包中,你可以通过设置 使每个函数(也是每个条件)成为一个组\Functional{scoping=true}
。
% --- latex code --- %
\documentclass{article}
\usepackage{functional}
\begin{document}
\Functional{scoping=true}
\IgnoreSpacesOn
\TlSet \lTmpaTl {a}
\TlVarLog \lTmpaTl % ---- a
\PrgNewFunction \SomeFun { } {
\TlSet \lTmpaTl {b}
\TlVarLog \lTmpaTl % ---- b
\IntCompareTF {1} > {0} {
\TlSet \lTmpaTl {c}
\TlVarLog \lTmpaTl % ---- c
}{ }
\TlVarLog \lTmpaTl % ---- b
}
\SomeFun
\TlVarLog \lTmpaTl % ---- a
\IgnoreSpacesOff
\end{document}
虽然 中有函数expl3
,但对它们的求值是从外到内。使用此新包,函数的求值是从内到外,这与其他编程语言(例如或 )functional
相同。以下是计算整数平方的另一个示例:Lua
JavaScript
---- lua code ----
function MathSquare (arg)
local lTmpaInt = arg * arg
return lTmpaInt
end
print(MathSquare(5))
print(MathSquare(MathSquare(5)))
% --- latex code --- %
\documentclass{article}
\usepackage{functional}
\begin{document}
\IgnoreSpacesOn
\PrgNewFunction \MathSquare { m } {
\IntSet \lTmpaInt { \IntEval { #1 * #1 } }
\Result { \Value \lTmpaInt }
}
\IgnoreSpacesOff
\MathSquare{5}
\MathSquare{\MathSquare{5}}
\end{document}
Lua
你会发现代码和代码之间几乎是一一对应的functional
,我想这个包就是你想要的。