从上一个问题,@egreg 表示:
参数类型
N
和n
是最常见的。前者表示参数必须是无支撑单标记,后者意味着该参数必须是标记列表。
对我来说这或多或少是清楚的,但看起来 L3 接口并没有强制用户定义的函数这样做,这是一个 MWE:
\documentclass{article}
\begin{document}
\ExplSyntaxOn
\cs_new:Nn \myFunc:N {<<#1>>}
\myFunc:N {test}
\ExplSyntaxOff
\end{document}
上述代码可以很好地编译,即使我将一个带括号的标记列表传递给函数,而myFunc:N
该函数显然被声明为严格采用无括号的单个标记。
这使得 L3 编程层的很大一部分,即函数定义和参数规范看起来就像一种简单的语法约定。叹。
为什么用户定义函数的参数类型没有像预期的那样强制执行?
冒号
奇怪的是,当我省略冒号时,编译器会抛出错误:
,例如,如果我将函数声明myFunc
为 oppositeto myFunc:N
。所以那似乎是强制执行的...
答案1
编程层expl3
仍然基于 TeX 语言,参数的查找按照 TeX 规则定义。
这些规则仅区分分隔和未限定参数。所谓expl3
的“函数”实际上是常规的 TeX 宏;变量根据其类型可以是宏或寄存器。
基础的\cs_new:Nn
函数仅处理未限定参数。它需要两个参数:一个是单个标记,它应该是函数的有效名称。包括签名;第二个参数应该是一个带括号的标记列表。
使用签名是为了为要定义的底层宏提供正确的参数文本,因为诸如
\cs_new:Nn \mymodule_foo:nn { #1 -- #2 }
最终变成
\def\mymodule_foo:nn #1#2{#1--#2}
(就像这样\newcommand
做一样)。可以定义名称中没有签名的函数,但通常不建议这样做:这些将是用户级命令,最好使用\NewDocumentCommand
它们。
另一方面,如果你这样做
\cs_new:Nn \mymodule_foo:N { --#1-- }
然后调用
\mymodule_foo:N {text}
expl3
TeX 会遵循自己的规则并毫无怨言地接受代码,尽管从这个角度来看编码是错误的。
为什么不强制以正确的方式指定参数(无论是带括号的还是不带括号的)?因为这通常是不可能的,而且无论如何,它都会在速度和效率方面带来很大的开销。
答案2
在 TeX 中 - 例外:LuaTeX 引擎 - 无法扩展地查看下一个标记以检查它是否是指示多标记参数的显式类别 1 字符标记(例如,类别 1 的花括号)。您需要使用类似 /based 的命令\futurelet
,这是一个赋值,这意味着所讨论的宏无法在扩展上下文中执行,例如、\write
、\message
、\csname..\endcsname
/ / /扩展等。\edef
x
e
f
o
除此之外:
如何“强制执行”,例如x
// e
/ f
-type o
-arguments?
引自维基百科:“在可计算性理论中,停机问题是根据任意计算机程序的描述和输入确定该程序是否会完成运行或继续运行的问题。1936 年,艾伦·图灵证明,不可能存在一种通用算法来解决所有可能的程序输入对的停机问题。“
某些e
-type-argument 标记可能构成基于扩展的计算机程序;某些e
-type-argument 标记可能来自用户级宏的参数,这些参数可视为计算机程序的输入。因此,检查/“执行”-type e
-argument 可能涉及提出一个相当通用的例程,用于检查构成 -type-argument 的标记的扩展e
(可能是基于扩展的计算机程序和该基于扩展的计算机程序的输入的组合)是否完全终止。
也许这并不完全是一个为图灵机提出一个通用算法来解决所有可能的程序输入对的停机问题的问题,但这让我想起了它。
如何“强制执行”,例如w
-type-arguments?
如何“强制执行”,例如T
/ F
-type-arguments?
顺便说一句 - 不要低估句法约定 - 它们对于调试有很大帮助。;-)
您可以定义(用户级)宏/控制序列,其中不需要指定参数签名 — 只需使用\cs_new:Npn
或其变体即可。p
-type-argument 表示参数文本,就像 一样\def
。