﻿/*
	© 2012-2017 FrankHB.

	This file is part of the YSLib project, and may only be used,
	modified, and distributed under the terms of the YSLib project
	license, LICENSE.TXT.  By continuing to use, modify, or distribute
	this file you indicate that you have read the license and
	understand and accept it fully.
*/

/*!	\file NPL.txt
\ingroup Documentation
\brief NPL 规格说明。
\version r3116
\author FrankHB <frankhb1989@gmail.com>
\since build 304
\par 创建时间:
	2012-04-25 10:34:20 +0800
\par 修改时间:
	2017-08-05 20:17 +0800
\par 文本编码:
	UTF-8
\par 模块名称:
	Documentation::NPL
*/


/*

@0 体例和适用范围：
引用标记参见 [Documentation::CommonRules @@0.1] 。
项目范围参见 [Documentation::ProjectRules @@1] 。
本文档适用于 NPL 及实现(@2.1.2) 。
编码细节和其它规范参见 [Documentation::Designation] 。

@1 整体设计：

@1.1 设计的基本原理、表达形式和抽象：
设计的出发点：构建一个可用计算机实现的语言。
原始目的：在以标准 C++ 环境（宿主实现）的程序框架中嵌入配置和脚本操作。
扩展目的：渐进地向独立的计算机软件系统演进，探究能适用于各个领域并以计算机实现的通用语言。
本文描述基于此出发点的 NPL(Name Protocoling Language) 及其参考实现。

@1.2 理论背景、工具和依据：
基本内容参见 [Documentation::CommonRules @@2.1] 。

@1.2.1 组织概念模型：
略。

@1.2.3 设计意义：
参见 [Documentation::Designation @@2.2] 。

@1.3 构建原则：
基本内容参见 [Documentation::CommonRules @@2.2] 。
其它参见 [Documentation::Designation @@2.3] 。

@1.4 领域设计原则：
适用于通用目的语言的设计。

@1.4.1 原则性描述：
关于设计和实现的哲学，同时作为一般规则约束设计和实现的阶段。

@1.4.1.1 本体论(ontology) ：
为使论述有效，约定本体论规则。
基本的本体论规则是约束逻辑系统构造的公理。

@1.4.1.1.1 正规性：
有效的陈述（如需求描述）应保证操作上可预期结果。
在此意义下，缺乏约束性的规则不可预期的风险是代价。
推论：规则应适当约定适用范围，以避免外延不清。

@1.4.1.1.2 存在性：
语义(semantics) 的存在体现本质。
仅仅应用语法(syntax) 规则不表示任何有效(@1.4.1.1.1) 的含义。

@1.4.1.1.3 名实问题：
名义概念的内涵和外延应被足够显式指定，避免指涉上的歧义，允许构造有效的陈述(@1.4.1.1.1) 。

@1.4.1.2 价值观：
价值观是关于价值判断的规则，其输出为二元的值，决定是否接受决策。
作为应对普遍需求场景的不同解决方案选型时的价值判断的抽象归纳，价值观被作为比较是否采用设计相关决策的全局依据。
以下陈述形式表达价值优先的选项，同时作为公理。

@1.4.1.2.1 变化的自由：
在明确需求的前提下，尽可能保证对现状按需进行改变的可行性和便利性。
适用于一般需求。
一般地，需求可能随着不可控的外部条件变化。假设已明确的需求不变只能适合相当有限的情形。积极应对变化能提供价值。
对计算机软件：尽可能避免不必要地损失可修改性，便于保障按需引入或除去接口(@2.1.2) 及其实现的自由。

@1.4.1.2.2 避免不必要付出的代价：
尽可能消除对满足需求无意义的代价，减少影响需求实现的整体成本。
适用于一般需求。
对计算机软件：不为不需要的特性付出代价。
Efficiency has been a major design goal for C++ from the beginning, also the principle of “zero overhead” for any feature that is not used in a program. It has been a guiding principle from the earliest days of C++ that “you don’t pay for what you don’t use”.
	-- ISO/IEC TR 18015

@1.4.1.2.3 最小接口原则：
在满足需求的前提下，尽量使用符合倾向减小实现需求代价（如减小设计工作量等）的单一良基关系下具有极小元的接口设计。
这是一条模式规则，依赖具体情形何者符合良基关系的极小元这条非模式规则作为输入。
实际使用时，非模式规则可以直接指定为二元关系的子集，或者一种良序的度量（如“公开函数声明数”“模块数”）。
注意规则指定的基数是对实现需求有意义的代价，因此不涵盖 @1.4.1.2.2 。
在确定的范围内尽可能少地提供必须的接口，避免不必要的假设影响接口适应需求的能力，同时减少实现需求的各个阶段的复杂性。
适用于一般需求的实现，特别地，强调“通用”目的时。
对需要在计算机上实现的人工语言设计：设计语言不应该进行功能的堆砌，而应该尽可能减少弱点和限制，使剩下的功能显得必要。
Programming languages should be designed not by piling feature on top of feature, but by removing the weaknesses and restrictions that make additional features appear necessary.
	-- Revised Report on the Algorithmic Language Scheme([RnRS]) & Revised Report on the Kernel Programming Language([RnRK])
其它各个领域中的实质等价表述包括：
用于安全系统设计的最小特权原则(@1.4.1.2.3.2) ；
用于自然科学理论设计的奥卡姆剃刀(Occam’s Razor) 原理，避免不必要的假设引入诉诸无知(argument from ignorance) 谬误。
另见 [Documentation::CommonRules @@3.1.3] 。

@1.4.1.2.4 关注点分离原则(separation of concerns) ：
局部设计的内容应和需求的陈述或其它隐含的设计前提分别一一对应。
适用于一般需求的实现。
这条规则利用需求和设计内容陈述中概念外延普遍蕴含的局域性(locality) ，提供给定代价下更多的可行性或求解给定问题时使用较小的代价，用于：
应对不可控复杂条件下使问题可解；
局部可复用现有解的子集。

@1.4.1.3 形而上学(metaphysics) ：
根据作为需求的 @1.4.1.2 ，归纳适用于通用目的语言应有的构成及其性质的设计规则，包括三条价值判断实现公理：
设计应尽量满足正确性(@1.4.1.3.1) ；
设计应尽量满足简单性(@1.4.1.3.4) 。
设计的正确性应优先于简单性。
注意和 Worse is better 或 The MIT approach 不同，设计的性质并非完全并列。
具备这些性质的设计可视为由价值判断(@1.4.1.2) 蕴含，预设前提为真的设计方法论(@1.4.1.4) 的实现。

@1.4.1.3.1 正确性(correctness) ：
设计应正确地反映需求，不在需求的基础上新增作为实现细节以外的不确定性。
无法确保满足正确性要求时，不应继续设计。
正确性包含可行性(feasibility) 。
若无法满足正确性，则需求输入存在问题。
正确性不包含但应逻辑蕴含设计的一些其它性质。若无法实现，则具体性质的定义存在问题。
保持正确性作为设计评价的首要依据以使决策简单，同时能符合价值判断(@1.4.1.2) 。

@1.4.1.3.1.1 完整性(completeness) ：
正确性应蕴含完整性。
由 @1.4.1.3.1 的推论：设计应包含完整的需求响应。

@1.4.1.3.1.2 一致性(consistency) ：
正确性应蕴含一致性。
由 @1.4.1.3.1 的推论：设计应保证一致性。

@1.4.1.3.2 简单性(simplicity) ：
在满足正确性的前提下，接口设计应尽量简单。
接口设计的简单性优先于实现的简单性。

@1.4.1.3.3 可修改性(modifiablity) ：
在满足需求的前提下，修改应尽可能少地有碍于其它的接口。
这是 @1.4.1.2.1 的推论。

@1.4.1.3.4 接口设计和实现分离：
语言设计独立于语言实现(@2.2) 。
这是同时应用 @1.4.1.2.3 和 @1.4.1.2.4 的推论。
这种分离允许避免抽象泄露(abstraction leaking) 。
典型地，使用提供接口抽象层作为必要构造的架构方法，即分层设计。

@1.4.1.2.5 最小特权原则(principle of least privilege) ：
除非有必要，接口抽象不提供满足需求以外的其它信息和资源。
这是 @1.4.1.2.3 在限制适用领域的等价表述之一，用于避免不必要的访问路径引入额外的安全(safety) 风险，更容易满足（针对恶意使用风险的）安全性(security) 和可信性保证相关的需求。
实质上提供例外的必要性之一是接口正确性：不附加不存在于需求以外的安全设计；根据 @1.4.1.3.3 ，这应是实现细节。

@1.4.1.3.6 可复用性(reusability) ：
语言实现包括库设计。
这是 @1.4.1.2.3 的推论之一，其非模式规则的输入为以下公设：
一般地，库设计和语言实现较单一的语言实现更复杂。
此前提条件由对需求工作量可行性分析中的度量验证总是成立。
推论：除非必要，不分离语言的实现和库的设计，避免复杂性。
全局意义上的不分离设计不违反 @1.4.1.2.4 。

@1.4.1.3.7 普适性(uniformity) ：
语言接口的设计应尽量避免特例。
同 [RnRK] 的设计原则 G1 。
这是 @1.4.1.2.3 的推论之一，以 @1.4.1.3.1.2 作为非模式规则输入。
无限制的特例要求指定更多的附加规则，而违反 @1.4.1.2.3 。

@1.4.1.3.8 可用性(usability) ：
易预测性：设计应允许但难以偶然实现的危险操作。
同 [RnRK] 的设计原则 G3 。
危险的操作指引起较大代价的不预期或无法预期结果的操作。
这是 @1.4.1.2.1 和 @1.4.1.2.2 的推论，包含两方面：
避免危险操作的风险是 @1.4.1.1.1 和 @1.4.1.2.2 的推论；
不直接禁止危险的操作以满足 @1.4.1.2.1 的要求。

@1.4.1.4 方法论(methodology) ：
方法论是严格独立价值判断(@1.4.1.2) 的规则。
不同的价值判断的结果作为方法论输入，决定是否适用此方法。
其它方法详见以下各节。

@1.4.1.4.1 避免不成熟的优化：
Premature optimization is the root of all evil.
适用于一般需求。
适时收缩理论长度以照顾可操作性（注意断言一个优化过早自身可能就是一个过早的优化）；
主动适应需求变更（不同时明确全部的具体需求，只限定需求范围：能使用计算机实现部分语义的任务）。

@1.4.2 语义方法：
形式语义方法：公理语义(axiomatic semantics) 、指称语义(denotational semantic) 和操作语义(operational semantics) 。
操作语义可分为在抽象机(@2.6) 中指定具体规约(@4.1) 步骤状态的结构化操作语义(structural operational semantics) （小步(small-step) 语义），及仅指定规约的输入和输出的自然语义(natural semantics) （大步(big-step) 语义）。
非确定语义：经验语义，不需要使用自然语言解释的部分。
本文档不给出形式语义。语言规则确定的经验语义可在一定条件下转写为上述形式语义方法表达的形式。

@2 基本概念和约定：
描述中可能涉及上下文相关的略称参见 @2.3 。

@2.1 通用约定：
关于“语言”补充的基本概念和约定，使用元语言语法 <相关范畴/上下文> 。
除非有其它说明，适用于任意上下文。

@2.1.1 [<自指><名词>] ：
实体(entity) ：任意被自然语言表达的目标；不需要通过自然语言先验定义；参见经验语义。
语义(semantics) ：参见经验语义。
经验(experience) ：参见哲学或一般等价的经验语义。
范畴(category) ：参见范畴论。
态射(morphism) ：参见范畴论。
归纳(induction) ：一种态射，可操作性参见经验语义。
方法学(methodology) ：一个归纳经验得到的范畴；参见哲学或一般等价的经验语义。
方法(method) ：方法学的一个子范畴；可操作性参见经验语义。
概念(concept) ：参见形式逻辑学。
上下文(context) ：一种概念范畴适用的态射；参见经验语义。

@2.1.2 [<非自指>] ：
形式(form) ：参见经验语义和数学。
<概念> 内涵：参见形式逻辑学。
<概念> 外延：参见形式逻辑学。
<概念> 定义(definition) ：确定概念内涵和外延的方法；参见任意一种形式逻辑学。
集合(set) ：参见 NBG 集合论。
序列(sequence) ：有序集合。
类(class) ：参见 NBG 集合论和范畴论。
真类(proper class) ：参见 NBG 集合论和范畴论。
<动词> 抽象(abstracting) ：通过经验语义定义概念范畴或集合的方法。
<名词> 抽象(abstraction) ：<动词>抽象的结果。
<动词> 封装(encapsulating) ：从某一个范畴中抽象一个子范畴的方法。
<名词> 封装(encapsulation) ：<动词>封装的结果。
接口(interface) ：一种封装，参见软件工程学。
实现(implementation) ：一种封装，参见软件工程学。
重用(reusing) ：参见经验语义和软件工程学。
不变量(invariable) ：满足某种等价关系（自反、传递、对称的二元关系）的实体。参见数学和契约式程序设计。
状态(state) ：可以和其它实体关联的、可在某个上下文中保持变化或不变的实体。同一状态总是保持变化或保持不变。状态变化的含义参见经验语义、数学或另行约定。
可变状态(mutable state) ：在某个上下文中可能映射到若干其它状态的状态。
不可变状态(immutable state) ：不是可变状态的状态。
<动词> 派生(deriving) ：基于重用的操作。
<名词> 派生(derivation) ：<动词>派生的结果。
<语言> 接口(<language>interface) ：和表达语义有关的语言的可见的特征。
<语言> 实现(<language>implementation)：对语言表达语义的表达。
<语言> 人类接口(human interface) ：语义仅对人类有意义（内容改变时可以导致语义的差异性），不提供为涉及作为图灵机实现的语言接口。
<语言> 机器接口(machine interface) ：对机器（或特定语言实现的特定部分）有意义的语言接口。注意不同语言实现组成部分可以不同。例如，对 C 预处理器而言， C 源代码中的空白符是机器接口，而对翻译器来说则不是。就源代码而言，机器接口总是人类接口的子集。
语言特性(language feature) ：作为功能提供的人类接口。

@2.2 领域约定：
适用于上下文 <NPL> 。
广义实体： <通用约定> 实体。语言抽象的目标，不另行定义（意义最终取决于自然语言）。
名称(name) ：一种特殊的广义实体，专用于指称另一个广义实体。
实体(entity) ：非名称的广义实体。
规则(rule) ：用于确定行为或其它规则的描述。
约束(constraint) ：可被形式表达，用于限制和明确行为的规则。不一定使用形式表达。
违反(violation) ：对约束指定的条件的不满足。
表示(representation) ：以一个符合某种形式的约束的实体指称另一个实体。
语言实现(language implementation) ：语言提供的接口的实现，是语言的表现形式，可以是具体语言实现或抽象语言实现之一。
具体语言实现(concreate language implementation) ：能最终完全表达为可预测的物理现象一一对应的表达可计算性的实现（如机器指令），一般应为程序。
抽象语言实现(abstract language implementation) ：非具体语言实现的语言实现。形式意义的标准定义的语言属于此类。
派生语言实现(derived language implementation) ：派生已有实现的部分或全部得到的语言实现。以下简作“派生实现”。
实现环境(environment of implementation) ：对应特定语言实现的特定不变状态（对机器来说可以是配置项，对人来说不确定，所以一般忽略）的集合。
行为(behavior) ：语言实现的外部表现。基于可操作性考虑，一般仅约束机器实现。
翻译(traslation) ：不同语言之间的变换，可作为语言实现的形式。
解释(interpretation) ：通过直接执行表现行为的具体语言实现的形式。
文法(grammar) ：描述语言的可形式化的规则。
语法(syntax)：描述语言的字面(literal) 结构而不考虑解释(interpretation) 或含义(meaning) 的规则、原理和过程。
语义(semantics)：语法以外的文法，可以约束含义的表达。
实例(instance) ：具有代表性含义的集合的元素。
代码(code)：任意有限的语言的实例片段。
伪代码(pseudo code)：抽象语言实现的语言的代码。注意习惯上和具体语言实现代码完全一致的代码可以不作为伪代码考虑。
程序(program) ：具体语言实现接受的以代码表示的输入，或被变换后对应的输出。
元语言(metalanguage) ：描述其它语言的语言。
对象语言(object language)：被元语言操作或实现的语言。
元编程(metaprograming) ：使用元语言编程。
反射(reflection) ：元语言和对象语言相同的元编程。
具现(reification) ：在对象语言中以数据模型作为关联实体以表示程序的语义。
诊断消息(diagnostic message) ：用于和用户交互的提示性信息。
未定义的(undefined) ：可能导致违反约束但不保证具有诊断消息的。表示置于规则下的行为等不可预测。
未指定的(unspecified) ：在各个实现中可能存在的。不应假定不同实现具有完全一致的特性。
由实现定义的(implementation-defined) ：取决于各个具体语言实现的，要求有文档说明。
由派生实现定义的(derived-implementation-defined) ：取决于各个具体派生实现的，要求除存在默认定义或被派生实现的部分有明确的文档说明。
语言特性(language feature) ：语言提供的功能接口，可以是具体语言特性或抽象语言特性之一。
具体语言特性(concrete language feature) ：完全没有派生语言实现定义的语言特性。
抽象语言特性(abstract language feature) ：非具体语言特性的语言特性。
过时的(obsolesence) ：不应继续使用的（接口/特性）。
废弃的(deprecated) ：过时的但因为兼容性等原因，暂时保留的、一般可提供替代的接口或特性。
外部环境(external environment) ：和程序及被翻译的程序没有交集的和实现环境无关的状态。

@2.3 略称：
仅在不致混淆时使用。
实现(implementation) ：语言实现。
环境(environment) ：实现环境。
派生实现(derived implementation) ：派生语言实现。

@2.4 NPL 实现模型：
NPL 是抽象的语言，没有具体语言实现(@2.2) ，但一些直接影响实现表现形式的规则被本节限定。
NPL 具体实现进行抽象解释(abstraction interpret) ，其目标不一定是程序(@2.2) 。

@2.4.1 实现的执行阶段(phase of execution) ：
一个 NPL 的完整实现应保证行为能符合以下的阶段（具体阶段不要求和实际实现中的一一对应，但应保证顺序一致）：
分析(analysis) 阶段：处理代码，取得适当的 IR（Intermediate Representation ，中间表示）；
代码生成(code generation) ：生成可被其它阶段执行的代码，称为目标代码；
运行：运行目标代码。
其中分析阶段是任意实现必要的，包含：
词法分析：必要时转换字符编码；转义并提取记号；
语法分析：语法检查（检验语法正确性(@2.5) ）并尝试匹配记号和语法规则中的语法元素(@3.4) ；
语义分析：语义检查（检验语义正确性(@2.5) ）并实现其它语义规则。
运行之前的阶段总称为翻译(translation) ，包含各个翻译阶段(phase of translation) 。
对有宿主语言支持的嵌入实现(embedded implementation) 或目标不是程序的情况，代码生成及之后的阶段不是必须的。
嵌入实现的宿主语言可直接运行语义分析的结果（中间表示）。
在语义不变的前提下，允许实现一次或多次翻译部分代码产生部分中间结果并复用。
其它可能的阶段由派生实现定义，但应满足所有阶段具有确定的全序关系，且不改变上述指定的阶段的顺序。符合这些条件的附加阶段称为扩展阶段。

@2.4.2 并发实现(concurrent implementation) ：
一个实现中顺序执行以上执行阶段的控制流称为一个执行线程(thread of execution) ，简称线程(thread) 。
一个实现在整个执行过程中可以有一个或多个线程被执行。是否支持多线程执行（多线程翻译和/或多线程运行）由派生实现定义。

@2.4.3 阶段不变量约束：
若某些状态在某个执行阶段 k 被唯一确定为不可变状态，且在之后的状态下是不变量，则此状态称为满足 k 阶段不变量约束的。

@2.5 正确性：
正确性规则包含语法正确性和语义正确性。
当正确性规则被发现违反时，实现进入异常执行状态。
异常执行的实现是否存在未定义行为由派生实现定义。

@2.6 实现行为：
实现的行为由具有非特定存储的抽象机描述。
若语义规则明确可以行为被忽略，则被忽略之后的实现行为与之前等价。
允许派生实现定义附加的等价性。
实现可能向用户以派生实现定义的方式输出诊断消息(diagnostic message) 。

@2.7 简单实现模型约定：

@2.7.1 嵌入宿主语言实现：
一个派生实现使用外部语言 L 简单实现模型 NPL-EMA ，若满足：
以 L 为宿主语言的嵌入实现，不包含扩展执行阶段(@2.4.1) ；
单一实现不支持多线程执行(@2.4.2) ，但允许多个实现同时在宿主中多线程执行。

@3 文法：
本章约定基本的 NPL 文法(@2.2) 规则中，包括语法及对应的基础词法。对应的语义单独列为一章(@4) 。
多态文法规则：派生实现可完全不提供本章明确定义的词法和语法构造的支持，仅当提供同构的替代文法且符合语义规则。

@3.1 基本概念：
字符(character) ：组成语言代码的最小实体。
基本翻译单元(basic transation unit) ：任意连续字符的有限序列（可以是空序列）。
翻译单元(translation unit) ：基本翻译单元的集合，之间满足由派生实现定义的规则。

@3.2 字符集和字符串：
字符集(character set) ：对一个实现而言不变的字符的有限集合。
基本字符集(basic character set) ：实现环境必须支持的字符集。具体由派生实现定义。
字符串(character string) ：字符集上的序列。
其它同 ISO/IEC 14882:2011 对 character 和 character set 的有关定义。

@3.3 词法规则(lexical rules) ：
约定元语言语法 <x> 表示词法元素 x ， ::= 表示定义， | 表示析取。
名称约定为在 NPL 中符合语法(@3.4) 约束的若干记号(@3.3.1) 的集合，一般可实现为可表达的字符串。

@3.3.1 基本词法构造：
<token> ::= <literal> | <$punctuator> | <$identifier>
词素(lexeme) ：代码中非空白符分隔的字符序列。
记号(token) ：词素的顶级分类。
属于记号的语法元素可以是以下的词法分类：
字面量(literal) ：一种记号，参见 @3.3.3 。
标点(punctuator) ：由派生实现定义的特定字符序列的集合，用于分隔其它记号，具有一定语义功能。
标识符(identifier) ：除字面量和标点以外的记号。
记号是可能附带附加词法分析信息的词素。词法分析(@2.4.1) 后得到的记号可以用词素映射到词法分类的有序对表示，但 NPL 不要求在此阶段保持分类也不限定表示的构造。
可以保证 ISO/IEC 14882:2011 的 identifier 的定义，或在上述标识符中插入字符 $ 构造得到的标识符属于 NPL 标识符。

@3.3.2 转义序列和字符序列：
<char-escape-content-seq> ::= <$single-escape-char> | <$escape-prefix-char><$escape-content-seq>
<char-seq> ::= <$literal-char> | \<char-escape-seq>

@3.3.3 字面量：
<literal-content> ::= <char-seq> | <literal-char-seq><literal-data>
<code-literal> ::= '<literal-content>'
<data-literal> ::= "<literal-content>"
<string-literal> ::= <code-literal> | <data-literal>
<literal> ::= <string-literal> | <$derived-impldef-literal>
代码字面量(code literal) ：以 ' 作为起始和结束字符的记号。
数据字面量(data literal) ：以 " 作为起始和结束字符的记号。
字符串字面量(string literal) ：代码字面量或数据字面量。
扩展字面量(extended literal) ：由派生实现定义的记号。
字面量：代码字面量、数据字面量、字符串字面量或扩展字面量。

@3.3.4 词法分析规则：
输入翻译单元，输出记号序列。
输出规则（按优先顺序）：
断行连接：反斜杠之后紧接换行符的双字符序列视为续行符，会被删除；
反斜杠转义：连续两个反斜杠被替换为一个反斜杠；
引号转义：反斜杠之后紧接单引号或双引号时，反斜杠会被删除；
字面量：未被转义的单引号或双引号后进入字面量解析状态，无视以下规则，直接逐字节输出原始输入，直至遇到对应的另一个引号。
窄字符空白符替换：单字节空格、水平/垂直制表符、换行符被替换为单一空格；回车符会被忽略；
原始输出：其它字符序列逐字节输出。

@3.4 语法 ：
本节指定 NPL 作为对象语言(@2.2) 的语法(@2.2) 。
约定元语言(@2.2) 的语法 x 表示语法元素 x ， ::= 表示定义， | 表示析取。
程序被作为语言实现(@2.2) 组成部分的语法分析(@2.4.1) 程序规约(@4.1) ，结果能确定其和一定的语法元素匹配。
规约时应进行语法规则的检查。

@3.4.1 基本语法构造：

@3.4.2 表达式(expression) ：
expression ::= atomic-expression | composite-expression | list-expression
表达式是受表达式语法约束的记号序列。
其中构成分别称为原子表达式(atomic expression) 、复合表达式(composite expression) 和列表表达式(list expression) 。
构成表达式的表达式是前者的子表达式(subexpression) 。

@3.4.2.1 原子表达式：
atomic-expression ::= token
原子表达式不能被表示为其它表达式的语法构成形式的复合。

@3.4.2.2 复合表达式：
composite-expression ::= token expression | expression token
符合表达式是原子表达式和表达式的复合，即语法意义上的直接并置连接(juxtaposition) ，不在被复合的表达式之间存在其它记号。
同一个表达式可能被按原子表达式出现的位置以不同的方式规约为复合表达式。允许的规约复合表达式的方式由派生实现定义。

@3.4.2.3 列表表达式：
list-expression ::= <left-list-bound> expression <right-list-bound>
<left-list-bound> ::= ( | <extended-left-list-bound>
<right-list-bound> ::= ) | <extended-right-list-bound>
列表表达式是使用 <left-list-bound> 和 <right-list-bound> 作为边界的表达式。
<left-list-bound> 和 <right-list-bound> 是不同的标点。
边界为 ( 和 ) 的表达式是基本列表表达式。其它可能的边界由派生实现定义，构成扩展列表表达式。

@3.4.4 语法形式(syntactic form) ：
语法形式是词法上满足特定形式(@2.1.2) 的语法构造。
除非派生实现另行指定，语法形式总是表达式。

@3.4.5 语句(statement) ：
以派生实现定义的标点结尾的表达式称为语句。
语句语法的分组(grouping) 规则以及是否隐式地作为列表表达式求值(@4.1) 由派生实现定义。

@3.4.6 简单文法约定：
一个派生实现使用简单文法 NPL-GA ，若满足：
翻译单元同基本翻译单元(@3.1) ；
只支持左原子表达式构成复合表达式(@3.4.2.2) ；
只支持基本列表表达式(@3.4.2.3) ；
标点为单个字符(@3.1) ；
不支持语句(@3.4.3) 。

@4 语义：
NPL 的语义规则(@2.2) 构成演绎系统(deductive system) ，通过对翻译单元(@3.1) 中的表达式(@3.4.2) 的求值(@4.1) 表达。
除非派生实现另行约定，仅使用表达式指定语义，系统的规约(@4.1) 规则即表达式的求值规则(@4.4) 。

@4.1 基本概念：
范围(range) ：一个连续区间。此处“连续”的概念由派生实现定义，默认参照数学的形式定义。
声明(declaration) ：引入单一名称的表达式。
声明区域(declarative region) ：对某一个声明及其引入的名称，通过声明区域规则(@4.3.1) 决定，可由词法分析实现(@5.5) 确定的关于这个名称有效的代码片段的最大位置范围。
有效名称(valid name) ：可以唯一确定指称的实体的名称。
有效命名实体(valid named entity) ：有效名称指称的实体。
名称隐藏(name hiding) ：若同一个名称在同一个位置属于超过一个声明区域，则应能通过名称隐藏规则(@4.3.2) 确定唯一有效的声明以指定有效名称和对应的有效命名实体，此时有效名称隐藏其它声明区域声明的名称，有效命名实体隐藏可以使用被隐藏名称指称的实体。
作用域(scope) ：声明区域的子集，满足其中指定的名称是有效名称。
生存期(lifetime) ：逻辑上关于可用性的连续区间的抽象，是一个闭集。
对象(object) ：表示可被逻辑上表达为连续存储的状态的集合且能明确生存期开始和终止的实体。
变量(variable) ：通过声明显式引入或通过演绎系统规则隐式引入的以名称指称的实体。
绑定(binding) ：引入变量的过程或结果，其中后者是变量的名称和引入的被变量表示的实体构成的有序对。
约束(bound) ：被绑定的。
常量(constant) ：满足某种不变量的约束以和不可变状态关联的实体。具体由派生实现定义。注意不和变量对立（表示不可变状态的变量可能是常量）。
值(value) ：表达式关联的不可变状态。
副作用(side effect) ：对表达式的值以外的表示的改变。
项(term) ：特定的演绎系统(deductive system) 特别是项重写系统(term rewriting system) 中处理的对象，是带有基本递归构造的元素，可对应语法中的表达式。
子项(subterm) ：具有递归形式构造的文法描述的参与构成项的项。
约束变量(bound variable) ：子项中出现的被约束的变量。
自由变量(free variable) ：子项中出现的非约束变量。
组合子(combinator) ：不是变量也不含相对于任何项的自由变量的子项。
转换(conversion) ：根据基于特定等价性（假设）前提的两个项之间的自反的演绎。
规约(reduction) ：两个项之间的、实例(@2.2) 是某个转换的子集的满足反自反的演绎。
作用(effect) ：具体实现规约表达式的结果，包括值的计算和副作用的产生。
求值结果(evaluation result) ：作用的子集，是求值得到的用于替换被求值的表达式的表达式或其它由派生实现定义的实体。
抽象求值(abstract evaluation) ：对表达式的不取得作用的规约。
具体求值(concrete evaluation) ：对表达式的取得作用的规约。
求值(evaluation) ：抽象求值或具体求值。
外部表示(external representation) ：具有特定形式的用于和外部环境(@2.2) 交互的表示(@2.2) 。
一等对象(first-class object) ：语言表达的中允许足够操作的子集，使用的判定准则和 [RnRK] Appendix B 约定一致。

@4.1.1 表示：
表示用于表现演绎实例、具体实现及其中一部分实体（如某个值）的状态。
注意变量不一定是可变状态的表示。
外部表示未指定，可由派生指定约定。

@4.1.2 演绎规则：
指定转换的演绎规则是转换规则。
指定规约的演绎规则是规约规则。
两两可转换的对象的传递闭包构成等价类，称为可转换等价类。除非另行约定，只讨论具有单一可转换等价类的转换规则的（抽象）重写系统。
对象之间的转换保持某种等价关系的等价变换(transformation) 。对象之间的规约是其中的子集，即以存在等价关系的一个对象替代另一个对象的有向转换。
若两个对象具有规约到相同结果的变换，这两个对象可连接的(joinable) 。
若任意两个对象等价蕴含对象可连接，则此重写系统具有 Church-Rosser 属性(Church-Rosser property) 。
若可从任意一个对象规约到的任意两个对象可连接，则重写系统具有汇聚性(confluence) 。
若可从任意一个对象的一步规约到的任意两个对象可连接，则重写系统具有局部汇聚性(local confluence) ，或称为弱汇聚性(weak confluence) 。
若可从一个对象规约到的任意两个对象可连接，则此对象具有汇聚性。
若可从一个对象的一步规约到的任意两个对象可连接，则此对象具有局部汇聚性，或称为弱汇聚性。
规约中可包括实现环境(@2.2) 的交互。
若规约用于求值，汇聚性限定为：满足任意以此规则变换前和变换后的项被分别规约时，两者的作用相等。

@4.1.3 状态和行为：
状态不变由实现定义的等价关系(@2.1.2) 决定。
除非派生实现另行指定，约定：
实现行为(@2.6) 总是可使用状态进行描述；
存在副作用为可观察(observable) 行为的必要条件。
若存在状态等价性以外描述的行为描述，由派生实现指定。
可观察行为如有其它外延，由派生实现指定；否则存在副作用是存在可观察行为的充分条件。
实现应满足实现行为(@2.6) 和语义蕴含的可观察行为等价；不严格要求按抽象机(@2.6) 实现操作语义。

@4.1.4 一等对象设计原理：
语言操作一等对象。
作为 @1.4.1.3.7 的实例，一等对象避免特殊规则，和 [RnRK] 设计原则 G1a 一致。

@4.1.4.1 引用(reference) ：
尽管满足 [RnRK] Appendix B 的准则(criteria)， 和 [RnRK] 及 Java 等语言明确要求的设计不同，一等对象即对象自身，不要求具有引用和被引用对象(referent) 的概念。
考虑此设计决策时关注的有以下几点依据：
首先，保证语言操作的一等对象只能通过引用进行抽象利用的仅仅是对“对象”的普遍预期操作的子集，削弱了一等对象描述（不一定和对象的值直接关联的）附加状态的抽象能力。
例如，仅以引用访问的一等对象无法预期对象是否具有存储以及基于存储的属性(property) 如大小(size) ；对生存期和所有权的确定也直接在形式上（而不只是实现上）依赖于附加对象外部的元数据，而不是被访问的对象自身的属性。
这意味一旦需要这些附加属性时，提供的额外的操作依赖附加的定义。同时要求假定普遍存在的作为间接抽象的引用和这些附加定义使语言的设计更复杂。
这种设计上的复杂性对语言的表达能力不是必要的。
而除了放弃要求普遍的引用以外的减小设计复杂性的方式，会显著减小实现普遍需求的抽象（如资源所有权语义([Documentaion::CommonRules @@2.3.4]) ）的表达能力，放弃普遍的引用更合适。
其次，要求普遍的引用的设计也引起实现缺陷。考虑到一般的引用访问总是需被实现为额外的（间接）操作，这种缺陷也不能被实现直接避免。
即便在设计以下引入等价引用的兼容层可能提升实现被复用的可能性，不需要通过引用表达的属性仍然存在，减小复杂性需要保留冗余的间接操作而损害性能等实现质量。
允许实现按需引入特定而非普遍的引用是更符合一般需求的决策。
第三，使用引用访问对象且保留同时以非引用的形式访问对象并非必要，因为满足以上准则实际上仅关心对象（类似作为表达式）直接关联的值，而非其它属性。
这也说明是否仅允许通过引用访问对象是实现细节而不影响一等对象的判定。
第四，基于以上讨论，一等对象仍然至少有两个分类：只关心对象的值的，和同时关心对象的其它属性的。后者允许更多的操作，且允许作为前者使用，反之无法直接保证。
并不需要修改一等对象的判定准则限定为后者并使前者依赖后者的定义，因为作为抽象，前者通常并非是后者的操作上进行限制得到（正相反，一般是通过补充约定假设得到）。
类似的一个例子是不可修改对象(nonmodifiable object) 可以但不必要是对应的可修改对象(modifiable object) 的子类型。
注意，此处的不引入普遍引用的设计仍允许特定一等对象总是以引用形式在对象语言中直接访问。

@4.1.4.2 其它普遍性质：
更一般地，基于和 [RnRK] 中讨论类似的其它实用性理由，定义一等对象的准则和设计决策还应满足以下几点：
第五，应使一等对象的定义和基于状态存储的对象的概念定义一致。
第六，应允许类型(@4.6.2) 在语言中被抽象为一等对象。
一等对象准则内不依赖类型的概念（而可依赖值域(value domain) ）以避免概念定义的循环依赖。
存在一些判定准则不符合这些要求，如 [RnRK] 中引用的 [Gu91] ：
“类型”未经定义直接定义出现在规则中，不满足以上最后一点；
显式地放弃了生存期的抽象，不满足上述第一点要求的对象一般属性的抽象能力。

@4.2 基本语义规则：
所有不需要诊断消息的规则由派生实现定义。
本节内的规则应不产生未定义行为。

@4.3 名称规则：
名称(@2.2) 和能标识特定含义、符合名称词法约束(@3.3) 的表达式(@3.4.2) 一一对应。
具体的外延由派生实现定义。
表示名称的表达式不同于名称，但在无歧义时，语言中可直接以名称代指表达式和对应的词法元素。

@4.3.1 声明区域规则：
对引入名称 n 的声明 D ，对应的声明区域始于紧接 n 的位置，终于满足以下条件的记号“)”（若存在）或翻译单元末尾（不存在满足条件的记号“)”）：
记号“)”和与之匹配的记号“(”构成的表达式包含 D ；
此记号之前不存在满足上一个条件的其它的记号“)”。

@4.3.2 可见(visible) 名称：
名称隐藏规则：若声明 D 是表达式 E 的子集，且不存在 D 的子集声明同一个名称，则 D 声明了有效名称，隐藏了 E 中其它同名的名称。
在声明区域中，没有被隐藏的名称是可见(visible) 的。有效名称实质蕴含可见名称。

@4.3.3 名称解析(name resoultion) ：
名称解析是通过名称确定名称指定的实体的过程。
名称解析包括名称验证(name verification) 和名称查找(name lookup) 。
不保证名称解析总是成功。
名称验证确定可见名称(@4.3.2) 的基础上确定名称是否有效。
名称查找是从已知有效名称确定唯一指称的实体的过程，仅在名称验证成功后进行。
不同名称经过名称查找的结果可能等效。等效的有效名称视为同一的，规则由派生实现定义。
以上约定以外的具体规则以及失败的行为由派生实现定义。

@4.3.4 命名空间(namespace) ：
命名空间是实体(@2.2) 。命名空间可以由名称指称。
是否实现命名空间为程序中可由用户指定可变的实体及求值环境(@4.6.1.1) ，由派生实现定义。

@4.3.4.1 指称(denotation) ：
总是没有名称指称的命名空间是匿名命名空间(anonymous namespace) 。
没有有效名称指称的命名空间是未命名命名空间(unnamed namespace) 。
注意匿名命名空间和未命名命名空间不同。前者可能是一个系统的默认约定，一般整体唯一存在（如全局(global) 命名空间）；后者只是对某些接口隐藏，可以有多个。
NPL 定义一个抽象的匿名命名空间，称为根命名空间。未命名命名空间的支持由派生实现定义。
NPL 约定一个在实现中的有效名称总是指称一个命名空间。有效名称指称的命名空间的同一性和有效名称的同一性(@4.3.3) 对应。

@4.3.4.2 成员(member) ：
除了用于指称的名称外，一个命名空间可以和若干其它名称关联。
通过派生实现定义的对命名空间的操作可以取得的名称是这个命名空间的成员。
若无歧义，命名空间的成员指称的实体也称为这个命名空间的成员。
命名空间直接包含成员，称为直接成员。
除了根命名空间和其它派生实现定义外，命名空间可以作为另一个命名空间的成员，此时命名空间内的成员（若存在）是包含其的命名空间的间接成员。
命名空间对成员的直接包含和间接包含总称为包含，是反自反的、反对称的、传递的二元关系。

@4.3.4.3 简单名称(simple name) 和限定名称(qualified name) ：
命名空间的直接成员(@4.3.4.2) 的标识符在这个命名空间中是有效名称，称为简单名称。
命名空间及其成员按包含关系依次枚举标识符组成的序列是一个名称，称为在这个命名空间中的限定名称。
根命名空间的限定名称称为全限定名称(fully qualified name) 。
限定名称的语法（如标识符之间的分隔符等）由派生实现定义。

@4.4 求值规则：
除非另行约定，以下讨论的排除求值副作用的重写系统具有汇聚性(@4.1.2) 。
这保证求值满足以下基本规则：
值替换规则：表达式的值的计算通过已知的子表达式的值替换决定。
除非派生实现另行约定，子表达式的值仅由求值得到，此时递归蕴含规则(@4.4.4.1) 中的求值依赖规则是这个规则的推论。

@4.4.1 求值顺序(evaluation order) ：
先序(sequenced before) 关系是两个求值之间存在的一种偏序关系(partial order) ，对实现中求值之间的顺序提供约束。
后序(sequenced after) 是先序的逆关系。
非决定性有序(indeterminately sequenced) 是先序或后序的并集。
无序(unsequenced) 是非决定性有序在求值二元关系全集上的补集。
非决定性求值规则：除非派生实现另行约定，递归蕴含规则(@4.4.4.1) 约定外的任意表达式的求值之间无序。
非决定性求值规则允许在语言中表达并发实现(@2.4.2) 。

@4.4.2 求值性质：
两个具体求值等价，当且仅当两者的作用相等。
两个求值等价，当且仅当作为具体求值时等价，或其中每个求值的变换实质蕴含另一个。
没有副作用的求值是纯的(pure) （仅有值的计算或抽象求值）。
值为被求值的表达式自身的具体求值或不包含变换为存在不等价求值的表达式的抽象求值为恒等(identity) 求值。
恒等的纯求值是空求值(empty evaluation) 。
作用是空集的表达式求值是空作用求值(null effect evaluation) 。推论：空作用求值是空求值。
语法形式(@3.4.4) 固定且求值总是空求值的表达式是空表达式(empty expression) ，这仅由派生实现可选提供。

@4.4.3 范式(normal form) ：
规范化形式(normalized form)，或简称范式(normal form) ，是由派生实现定义的表示(@2.2) ，被一组规约(@4.1) 规则确定，满足：
通过有限的规约步骤后得到；
按规约规则，规范形式上不存在不和空求值等价(@4.4.2) 的进一步规约。
在具有 Church-Rosser 属性的重写系统(@4.1.2) 中，一个对象若具有范式则唯一。
表达式在得到规范形式后规约终止，且蕴含求值终止。
得到范式的规约步骤称为规范化(normalization) 。
若表达式规约总是能得到规范形式（求值总是能在有限规约步骤后终止），则具有强规范化(strong normalization) 性质。
实现应避免引起无法保证强规范化性质的操作（如直接无条件的递归规约调用）。
除非派生实现另行约定，不保证强规范化性质。
保证得到范式的规约是规范化规约。

@4.4.3.1 其它规范化中间表示：
第一个子表达式（头表达式）是范式的表达式是 HNF（Head Normal Form ，头范式）。
头表达式是可直接求值为范式的表达式是 WHNF（Weak HNF，弱头范式）。
约定求值到 WHNF 提供保证强规范化性质的一般手段，可用于非严格求值(@4.4.4.5) 。
WHNF 的头表达式是操作符(operator) ，对应的 HNF 的头表达式是合并子(combiner) ；另见 @4.5.3 。
WHNF 中除了操作符以外的子表达式是操作数(operand) 。

@4.4.4 组合求值：
表达式和子表达式之间的求值需满足一定约束。

@4.4.4.1 递归蕴含规则：
除非派生实现另行约定，表达式和子表达式之间的求值满足以下递归蕴含规则：
求值依赖规则：表达式被求值实质蕴含子表达式(@3.4.2) 被求值。
顺序依赖规则：子表达式求值先序(@4.4.1) 所在的表达式求值。
平凡求值规则：指定一个表达式是平凡求值(@4.4.2) 实质蕴含其子表达式的求值被指定为平凡求值。

@4.4.4.2 严格性(strictness) ：
若表达式的任意子表达式的求值总是非空求值(@4.4.2) 且先序表达式求值，则这个表达式的求值是严格的(strict) ；反之，求值是非严格的(non-strict) 。
推论：严格求值满足顺序依赖规则。
非严格求值在规约时可保留未产生作用（通常即未被求值）的部分子表达式，允许实现根据先序的求值作用确定的选择性求值，即包括未指定是否作为空求值(@4.4.2) 的子表达式求值，如分支判断或短路求值。
例如： C 语言的条件表达式存在可能未被求值的操作数(@4.4.3.1) ，属于非严格求值； ++ 表达式不作为完全表达式(full expression) 时，副作用可超出此表达式的求值（不满足顺序依赖规则），也是非严格求值。
表达式经过严格性分析(strictness analysis) 确定是否严格求值，通过严格性分析器(strictness analyzer) 在语义分析(@2.4.1) 时实现。
通过保留未求值的部分子表达式为特定的数据结构（称为中间值(thunk) ）待延迟求值，可子表达式值的实现按需传递(@4.4.4.5) 。

@4.4.4.3 顺序求值：
明确的词法顺序可为同一个表达式的若干子表达式提供一致的有序求值策略：从左到右或从右到左。为一致性，不需要考虑其它特定顺序作为一般规则。
递归文法表示的表达式和子表达式之间存在相对内外顺序：子表达式在表达式的内部。此求值顺序可对应表达式树的遍历顺序。

@4.4.4.4 替换策略：
对应项的规约规则的表达式的重写规则由派生实现定义，基本的可选项包括：
名称替换：保证替换前后项对应的名称不变；
实体替换：保证替换前后项关联的实体不变；
值替换：保证替换前后项关联的表达式的值满足实现定义的相等关系。
引用替换：保证替换前后项关联的表达式的值以实现定义的方式引用同一实体。

@4.4.4.5 求值策略：
组合严格、顺序求值和替换策略可得到不同性质的求值策略。
除非派生实现约定，表达式求值策略可以随具体语法形式(@3.4.4) 不同而不同。
典型性质组合如下：
严格求值：
应用序(applicative order) ：以最左最内(leftmost innermost) 优先的顺序求值。
按值传递(pass by value) ：使用值替换的严格求值。
按引用传递(pass by reference) ：使用引用替换的严格求值。
共享对象传递(pass by shared object) ：使用的共享机制以及对象和值或引用的关系由派生实现定义。
部分求值(partial evaluation) ：允许求值分为多个阶段(phase) 。
非严格求值：
正规序(normal order) ：以最左最外(leftmost outmost) 优先的顺序求值。
按名传递(pass by name) ：使用名称替换且保持作为名称的表达式最后被替换的求值。
按需传递(pass by need) ：按名传递但允许合并作用相同的表达式。
非决定性求值(@4.4.1) ：
完全归约(full reduction) ：替换不受到作用之间的依赖的限制。
按预期传递(pass by future) ：并发的按名传递，在需要使用参数的值时同步。
乐观求值(optimistic evaluation) ：部分子表达式在未指定时机部分求值的按需求值，若超出约定时限则放弃并回退到按需求值。

@4.4.6 可选求值规则：
应满足的本节上述约定的最小求值规则和语义外的具体求值规则和语义由派生实现定义。
派生实现的求值可满足以下节指定语义，此时应满足其中约定的规则。

@4.5 λ 完备语义和对应语法：
作为通用语言，求值规则表达的系统可具有和无类型 λ 演算(untyped lambda calculus) 对应的形式和计算能力。
基于此语义的派生实现应允许以下几种互不相交的表达式集合：
名称表达式(name expression) ；
匿名函数(anonymous function) ；
函数应用(function application) 。
具体含义见以下各节。
注意 λ 演算可保证以上除函数应用外求值的强规范化，但此处不要求，参见 @4.4.3 。

@4.5.1 名称表达式 ：
名称表达式是表示变量的 λ 项。
原子表达式(@3.4.2.1) 的由派生实现定义的非空子集是名称表达式。其它作为名称表达式的表达式语法形式(@3.4.4) 由派生实现定义。
名称表达式不被进一步规约；其求值是值替换规则(@4.4) 的平凡形式。

@4.5.2 函数(function) ：
特定的由派生实现定义的表达式是操作符(@4.4.3.1) ，称为匿名函数表达式，简称匿名函数。
操作符可以捕获(capture) 若干有效名称及对应的实体，即这些名称可在函数中使用并唯一确定指称。
若匿名函数所在作用域(@4.1) 的存在同名的名称，则被捕获的名称隐藏(@4.1) 。
被绑定(bound) 在操作符上且被捕获的名称指称的实体是函数的形式参数(formal parameter, parameter) 。
派生实现应在仅有名称表达式不同的两个函数之间定义等价规则，以满足 α-转换(alpha-conversion) 规则。
除非派生实现另行约定，函数表达式不需要被进一步规约，此时其求值是值替换规则(@4.4) 的平凡形式。
名称表达式可指称匿名函数的实体，替换函数同时保持等价的(@4.4.2) 求值，这样的名称表达式是具名函数表达式(named function) ，简称具名函数。
匿名函数表达式和具名函数表达式统称函数表达式，简称函数。

@4.5.2.1 过程(procedure) ：
过程是操作符具现(@2.2) 的实体。函数表达式的求值结果(@4.1) 和过程实体以派生实现定义的方式关联。
具体实现中的过程可能为子例程(subroutine)、协程(subroutine) 、续延(continuation) 等形式的一种或多种，由派生实现指定。
注意过程不一定具有可被对象语言(@2.2) 直接表达的一等(first-class) 函数而在元语言(@2.2) 中可能是，如无限制续延(undelimited continuation) 。

@4.5.2.2 λ 抽象(lambda abstraction) ：
λ 抽象是典型的操作符，是 λ 演算中的基本构成之一。
λ 抽象创建的过程是应用合并子(@4.5.3.2) 。

@4.5.2.3 vau 抽象(vau abstraction) ：
Vau 抽象是 vau 演算中的基本构成之一。
Vau 抽象创建的过程是操作合并子(@4.5.3.2) 。
使用 vau 抽象可实现 λ 抽象，如 Kernel 语言提供的 $vau 操作合并子(@4.5.3.2) 。

@4.5.3 函数合并(function combination) ：
形如 E1 E2... 的复合表达式(@3.4.2.2) E ，当且仅当 E1 是函数时， E 是函数合并表达式，简称函数合并。
项列表 E2... 是操作数(@4.4.3.1) ，在 E 被求值时以操作数(@4.4.3.1) 替换函数的形式参数。
函数合并的求值是替换规则(@4.4) 的非平凡形式。
若替换操作数 E2... 被求值，函数合并 E 是函数应用表达式，简称函数应用。替换的操作数和形式参数一一对应。
函数应用的求值的操作数结果是实际参数(actual argument, argument) 。
若操作符是 λ 抽象， E2... 视为一个整体，则函数应用替换规则对应 λ 演算的 β-规约(beta-reduction) 规则。
其它函数合并使用的替换规则由派生实现指定。
派生实现应指定函数合并规约(@4.1) 的结果是规范形式(@4.5.2)，它对应的值称为函数值。
函数应用中，替换形式参数(@4.5.2) 为实际参数(@4.5.2) 的过程蕴含对实际参数的值的计算的依赖，即参数的值的计算先序函数应用的求值；但其它求值顺序没有保证。

@4.5.3.1 函数调用(call) ：
使用指定实际参数(@4.5.2) 作为形式参数(@4.5.2) 并求值的函数应用是函数调用。
函数调用确定副作用的边界：保证参数表达式在函数应用被求值之前被求值。
典型实现的函数指称过程，函数调用为过程调用。

@4.5.3.2 函数应用合并子：
除非另行约定， NPL 假定函数应用满足以下典型情形，即函数应用的操作符一般求值为以下合并子(@4.4.3.1) 之一：
对操作数(@4.4.3.1) 直接操作（而不是对变量求值的）的合并子是操作合并子(operative combiner) ，简称操作子(operative) ；
依赖对实际参数(@4.5.2) 进行求值的合并子是应用合并子(applicative combiner) ，简称应用子(applicative) 。
同时，应用子对应蕴含一个一一对应的底层(underlying) 操作子。

@4.5.3.4 活动记录(activation record) ：
函数调用(@4.5.3.1) 时以活动记录引用涉及的变量。
每一个调用关联其中的一个帧(frame) 。

@4.5.4 λ 求值策略：
在变量(@4.5.1) 绑定值后，兼容 λ 演算规约语义的表达式的具体求值(@4.1) 根据是否传递操作数对使用按需传递(@4.4.4.5) 的求值策略的情形分为三类：
（完全）惰性求值(lazy evaluation) 、部分惰性求值和热情求值(eager evaluation) 。
其中，惰性求值总是使用按需传递，热情求值总是不使用按需传递，部分惰性求值不总是使用或不适用按需传递。
在保证不存在非纯求值(@4.4.2) 时这些求值的作用(@4.1) 没有实质差异。存在非纯求值时，使用的 λ 求值策略由派生实现定义。
非严格求值(@4.4.4.5) 严格蕴含惰性求值。两者经常但不总是一致，例如，实现可能并行地热情求值，并舍弃部分结果以实现非严格求值。
热情求值蕴含严格求值(@4.4.4.5) 。两者也经常但不总是一致，例如，实现可能使用应用序严格求值。但因为非严格的热情求值缺乏性能等可局部优化的实用动机，这种不一致的情况通常不作为附加的语言特性提供（而仅为简化实现默认作为全局策略使用）。
由于实现可能确定特定表达式的作用对约定必须保持的程序行为(@4.1.3) 没有影响而可能省略求值，按抽象机(@2.6) 语义的严格求值在实际实现中通常是不必要的。
惰性求值可通过中间值延迟求值(@4.4.4.2) 实现。

@4.6 表达式关联实体：

@4.6.1 上下文(context) ：
上下文是表达式关联的状态的特定集合（注意不是 @2.1.1 约定的自指概念）。
一个上下文是显式的(explicit) ，当且仅当它可以通过名称表达式(@4.1.5) 访问。
一个上下文是隐式的(implicit) ，当且仅当它不是显式的。
确定上下文的状态或对可变上下文的修改称为对上下文的访问(access) 。
过程实体(@4.5.2) 决定函数表达式(@4.5.2) 关联的上下文。
本节以外其它具体规则由派生实现定义。

@4.6.1.1 求值环境(evaluation environment) ：
求值环境是在求值(@4.1) 时可访问的隐式上下文，是由变量的绑定(@4.1) 构成的集合。
按绑定的定义，求值环境即变量的名称和通过声明引入的被变量表示的实体构成的映射。
不和实现环境(@2.2) 相混淆的情况下，简称（变量或绑定所在的）环境(environment) 。

@4.6.1.1.1 实现环境提供的求值环境：
实现环境可能在实现以外提供附加的求值环境(@4.6.1.1) 作为任务通信的机制，如环境变量。
除非派生实现另行约定，语言支持的求值环境和这些机制蕴含的求值环境的交集为空。语言可以库的形式提供 API 另行支持。

@4.6.1.1.2 函数和函数应用的求值环境：
在典型的对象语言中 λ 抽象(@4.5.2.2) 中指定的替换构造具有局部作用域(local scoping) ，其中可访问 λ 抽象外部环境的变量，对应求值环境为局部环境(local environment) 。
在基于词法作用域(lexical scoping) 的对象语言中，引入 λ 抽象对应的语言构造支持捕获引入函数时所在的作用域的环境，称为静态环境(static environment) 。
Vau 抽象(@4.5.2.3) 进一步支持在局部环境中提供访问函数应用(@4.5.3) 时的求值环境，即动态环境(dynamic environment) 的机制。

@4.6.1.2 互操作上下文(interoperation context) ：
用于互操作的和求值(@4.1) 关联的隐式上下文是互操作上下文。
典型的实例为由 ISA 约定的通用架构寄存器的状态，可能需要在函数调用(@4.5.3.1) 或任务切换过程中保存和重置。
除非派生实现另行约定，语言不提供访问互操作上下文的公开接口。

@4.6.2 类型(type) ：
上下文中和表达式直接关联或间接关联的元素，满足某个执行阶段的不变量约束(@2.4.3) 。
和表达式直接关联的类型满足起始阶段不变量约束，称为静态类型(static type) 。
和表达式的值(@4.1) 关联的类型满足运行阶段(@2.4.1) 的不变量约束，称为动态类型(dynamic type) 。
其它可能存在类型或实现执行阶段的扩展由派生实现定义。
称为类型的具体实体和之间的关联由派生实现的类型系统(type system) 规则指定。

@5 语言实现：
当前维护的派生语言为 NPLA ，是 NPL 的抽象语言实现，约定以下附加规则。
NPLA 的参考实现 NPLA1 是具体语言实现，约定特定于当前参考实现的附加规则和实现。
NPLA1 解释实现参见 @6 。
虽然 NPLA 没有给出形式语义(@1.4.2) ，但 NPLA 实现中包含的 API 部分地提供和形式语义方法对应的支持：
通过回调对应依赖宿主语言(@5.2) 实现作为描述的指称语义；
在回调内对上下文进行操作，对应小步语义；
在回调内复用其它接口，对应大步语义。
NPLA 可支持非固定的规约规则集合，以 API 的形式体现，详见 @5.5.4 ；另见 @5.4.4 。
具体实现的编码风格导引参见 [Documentation::CommonRules @@5] 。

@5.1 NPLA 领域语义支持：
位(bit) ：表示二进制存储的最小单位，具有 0 和 1 两种状态。
字节(byte) ：基本字符集中一个字符需要的最少的存储空间，是若干位的有序集合。
八元组(octet) ： 8 个位的有序集合。

@5.2 NPLA 约定：
使用宿主语言为 ISO C++11 的简单实现模型 NPL-EMA(@2.7.1) 。
使用语法 NPL-GA(@3.4.5) 。
宿主语言对象的值描述状态且宿主语言要求的对 volatile 左值的操作也属于可观察行为(@4.1.3) 。
名称仅被实现为字符串。
扩展字面量(@3.3.3) 包括以 '#' 、 '+' 、 '-' 起始的但不全是 '+' 或 '-' 组成的长度大于 1 的标识符或十进制数字字符起始的标识符构成的字面量。
动态类型同静态类型。
规范形式(@4.4.3) 是特定类型的 C++ 对象。
名称解析失败(@4.3.3) 可被忽略而不终止(@4.4.3) 实现演绎；
保证名称表达式求值的强规范化(@4.4.3)。
不要求提供命名空间(@4.3.4) 实现的可变实体。
一字节占用的位和宿主环境一致（至少占用 8 个二进制位）。
存在不保证先求值的子表达式(@3.4.2) 的形式是特殊形式(special form) 。
不保证求值都是纯求值；非特殊形式使用热情求值；其它情形使用热情求值或惰性求值(@4.5.4) 由具体特殊形式约定。
除非另行约定，实现函数(@4.5.2) 的宿主数据结构生存期要求默认同宿主语言，即循环引用可能行为未定义，不保证内存安全，不要求实现跟垃圾回收和区分强弱引用。
除非派生实现另行约定， NPLA 约定仅有具有以下情形的程序引起未定义行为：
互操作时在宿主语言中引起未定义行为；
违反资源所有权语义([Documentaion::CommonRules @@2.3.4]) 约束的操作，包括但不限于：
	违反内存安全(@5.2.2) 的操作；
	除非另行约定，构造任意的循环引用。

@5.2.1 类型映射(type mapping) ：
因需提供 C++ 互操作性支持，所以明确约定实现中部分实体类型一一对应的 C++ 类型：
名称以 string 类型(@5.3.1) 表示。
类型映射使用的类型所在的命名空间由实现(@5.4.1) 约定。
类型映射的目标可能是类型别名。
类型系统是开放的，可能提供不被对象语言支持的宿主语言类型和值，如中间值(@5.4.5) 。
因此，没有类似 Kernel 设计中的可扩展性（ [RnRK] 原则 G1b ）和封装性（ [RnRK] 原则 G4 ）的约束。

@5.2.2 存储和对象模型：
因需提供宿主语言(@5.2) 互操作性支持， NPLA 的基础存储模型和对象模型和 ISO C++11 相同。
在此情况下对象都是固定(pinned) 的，即对象在生存期内具有确定不变的地址。派生实现可约定扩展作为例外。
被求值的表达式的内部表示即项(@5.4.4) 或环境(@5.4.3) 中的对象持有 NPLA 对象的所有权。所有权被前者独占的 NPLA 对象是临时对象。
求值结果(@4.1) 可能包含对象，称为结果对象(result object) 。求值结果和结果对象和 ISO C++17 （由提案 P0135R1 引入）中的概念对应。
函数调用(@4.5.3.1) 时以活动记录(@4.5.3.4) 保持被引用对象的所有权。活动记录及其帧的具体结构、维护方式和生存期由派生实现定义。
因为宿主语言函数调用实现（典型地，调用栈(call stack) 及其中的栈帧）不提供可移植的互操作性，除非另行约定， NPLA 的活动记录设计不需要保证直接对应关系。
用户代码应注意超出生存期的不满足（非并发）内存安全(memory safety) 访问造成宿主语言的未定义行为。

@5.2.2.1 NPLA1 内存安全性保证：
NPLA1 中，确定地引入上述非内存安全的操作应仅只包括引入间接值(@5.4.6) 或其它派生实现指定类型的值的操作：
调用引入间接值的 NPLA API(@5.5.5.2) ；
调用 NPLA1 中其它取 YSLib::ValueNode 存储值的间接值的 API 。
通过一定的约定和限制，前者在 NPLA1 实现中仍能保证内存安全性，参见 @6.2.7 。
后者主要包括实现中调用的明确取无所有权引用的 API ，参见 @6.6 。

@5.3 NPLA 实现架构：
NPLA 实现为对数据结构的管道-过滤器(pipe-filter) 架构模式的处理框架。每个处理节点实现一个或若干个阶段(@2.4.1) 。
这里的数据结构是语言实现的 IR(@2.4.1) 或通过代码生成(@2.4.1) 得到的代码。在 NPLA 实现中后者是可选的。
本节指定首先经过两个前端(frontend) ，之后的处理见 @5.4 。

@5.3.1 词法分析：
参见 @3.3.4 和参考实现模块 Lexical 。
Lexical 模块在 namespace NPL 通过别名声明引入 YSLib::string 类型和 YSLib::string_view 类型。

@5.3.2 语法分析：
参考实现模块 SContext ，以 AST（Abstract Syntax Tree ，抽象语法树）作为保存分析结果的 IR 。
派生实现可能检查更多语法规则。
SContet 模块在 namespace NPL 通过别名声明引入以下 YSLib 类型名称：
ValueObject 、 ValueNode 、 observer_ptr 和 LoggedEvent 。
关于这些类型，另见 [Documentation::YSLib @@3.16] 和 [Documentation::YSLib @@3.2] 。
语法分析也提供了 TermNode 类型及其操作。

@5.4 NPLA 公共实现：
本节以外其它 NPLA 实现使用的接口详见模块 NPLA 和以下章节(@5.5) 。
本节中除之前在 @5.3.1 和 @5.3.2 中出现的名称及 @5.4 中引入的类型名称（都在命名空间 NPL 中）外，其余 C++ 名称使用限定名称以避免混淆。
本节中的 API 都位于模块 NPLA ，详见 @5.5 。
另见 @5.8 。

@5.4.1 类型映射(@5.2.1) 实现：
类型映射使用的 C++ 类型在 namespace NPL 中声明，从 namespace YSLib 引入。
一些类型如 string 、 ValueNode 和 ValueObject 在词法分析(@5.3.1) 和语法分析(@5.3.2) API 中引入，被以下章节的实现使用，成为实际的映射目标。
以下章节 @5.4.2 和 @5.4.5 提供的节点或中间值(@4.4.4.2) 类型(thunk type) 是类型映射的目标(@5.4.1) 。

@5.4.2 IR 节点数据结构：
NPLA 实现使用节点(node) 数据结构表示实现使用的 IR 中间表示递归的构造，如 SContext 产生的 AST 的节点和语义分析使用的项。
这样的节点类型为 TermNode ，也用于表示单一的树（如整个 AST(@5.B.1) ）。
NPLA 实现语义规则时对 TermNode 进行处理，包括节点上的规约(@4.1) ，即树规约(tree reduction) 。
当前 TermNode 是 ValueNode 的别名。其中可能有子节点且包含值对象 Value 数据成员，详见 @5.4.4 。
树规约可按需添加或删除 TermNode 的子项。具体添加或删除的时机未指定，取决于具体的规约算法。
除最后的代码生成（若需要），规约时每个子表达式的树的结构总是在此表达式的根节点保持不变（被删除前保证表达式总是对应一颗树），且源于语法分析的节点名称不会被修改。
TermNode 中存储的值可引用其它节点共享部分数据形成 DAG（Directed Acyclic Graph ，有向无环图），规约为图规约(tree reduction) ，但这不属于一般的规约规则。注意实现应避免形成非 DAG 的共享，以保证不出现资源的所有权([Documentation::CommonRules @@2.3.4]) 的冲突。

@5.4.3 上下文和环境数据结构：
上下文(@4.6.1) 使用 ContextNode 类表示。
ContextNode 保存环境中的对象，提供求值环境(@4.6.1.1) 对象的表示。后者以 NPL::Environment 类表示，其中包含指定局部变量绑定的映射。
上下文对环境具有共享所有权(@5.2.2) ，通过环境对象的引用可以取指向它的 shared_ptr 实例。
环境对象在对象语言中作为引用值，传递环境不直接复制环境对象。另见 @4.1.4.1 。
NPL::Environment 支持定制名称解析(@4.3.3) 和名称解析的重定向，其中包含以下相关的数据成员：
Redirect ：重定向算法；
Resolve ：名称解析算法；
Parent ：作为可在运行时确定类型的父环境环境引用，用于重定向算法的实现。
默认的名称解析算法 NPL::Environment::DefaultResolve 首先查找局部变量绑定；若失败，调用 Redirect 进行重定向，从 Parent 中取目标环境代替环境后代替环境继续使用其中的名称解析算法查找，直至没有可重定向的目标。
默认的重定向算法 NPL::Environment::DefaultRedirect 依次检查重定向目标的宿主值(@5.4.4) 类型为如下之一：
EnvironmentList；
observer_ptr<const Environment> ；
shared_ptr<Environment> ；
weak_ptr<Environment> 。
其中， EnvironmentList 为 vector<ValueObject> 的别名，表示一个环境列表，作为父环境时可用于递归重定向。
和 Kernel 类似，默认的重定向算法默认使用 DFS（Depth-First Search ，深度优先搜索）遍历目标。
对象语言中的环境引用类型的宿主类型是非递归的重定向目标类型。
宿主值类型 observer_ptr<const Environment> 通常用于内部实现而不要求所有使用环境的操作支持。
作为一等对象(@4.1) 的环境引用的一般表达式值中，应根据是否需要具有所有权区分使用这些宿主类型的环境引用。
相关 API 参见 @5.5.8 。

@5.4.4 表达式的表示和求值：
TermNode 的子节点是子项的表示(@2.2) ，通常作为子表达式(@3.4.2) 的实现。
TermNode 的 Value 数据成员是 ValueObject 类型的对象，用于表示对象语言（ NPLA 实现）中表达式或对象储存的值，或者包装的中间值(@4.4.4.2) 。
此外，值可以是具有 TermNode 子项的列表(list) 数据结构，详见 @5.5.4.4 。相关操作参见 @5.1.5.1 。
NPLA 表达式或其求值得到的值以若干个 TermNode 、 TermNode 子项或 Value 数据成员表示；其中被求值的表达式应总能使用一个 TermNode 表示。
求值结果(@4.1) 也用 TermNode 表示，以支持直接基于项的替换操作实现求值。
表示值的 TermNode 是宿主语言对象具有的特定动态类型的值是宿主值(hosted value) ，可包括 Value 数据成员和子节点中的各个 Value 数据成员中所有被擦除类型存储的对象。典型情况下， Value 数据成员对应单一的宿主值。
NPLA 表达式求值取得的范式(@4.4.3) 总是其表示（是一个 TermNode ）中的子项或 Value 数据成员之一，详见 @5.5.4.4.2 。
TermNode 可能不直接表示表达式，如表示中间值(@5.4.5) 的情形。 NPLA 的范式不会使用这些形式表示。
作为 @4 的扩展，作用于非表达式表示的项上的规约规则不是求值规则。

@5.4.5 中间值：
中间值(@4.4.4.2) 可在 TermNode 的 Value 数据成员中存储。
和求值结果(@4.1) 及其它情形存储的对象不同，中间值可能参与特定的规约作为求值的中间步骤的表示。
为区分中间值和被映射其它值，约定中间值具有特定的类型。中间值类型不是其它 NPLA 外类型的别名，但考虑由其它类型转换或构造。
其中，记号值(@5.4.5.1) 和延迟求值项(@5.4.5.2) 都可表示未求值的表达式，但求值机制不同。

@5.4.5.1 记号值：
TokenValue 类型表示记号(@3.3.1) 的值，可使用 string 类型的值构造。
记号值对应的词素(@3.3.1) 的表示是字符串，即 string 类型。
记号值和词素在逻辑上非空，但因为外部表示未指定(@4.1.1) ，不保证在 API 中取得的这些类型对应非空串，因此除特定的内部实现外不省略空串检查。
和字符串值不同，记号值求值的结果不会继续是记号值，以避免不经意的递归求值或无法和宿主语言字符串值区分的情形出现。
但在 API 层次上，记号值的求值不排除无限循环或递归，不保证对应的项作为表达式时具有强规范化性质(@4.4.3)。实现需注意保证作为名称表达式时满足强规范化要求(@5.2) 。
表示一个未被求值的非字面量(@3.3.3) 记号的记号值称为符号(symbol) 。
记号值的相等性由等价于其对应的词素的相等性。
记号值可出现在词法分析(@5.3.1) 阶段，由单独的规约过程(@5.5.4.3) 通过调用 NPL::TokenizeTerm 转换词素得到。
记号值相关 API 参见 @5.5.3.2 。

@5.4.5.2 延迟求值项：
DelayedTerm 类型表示被延迟求值的项的值，可使用 TermNode 类型的值构造。
延迟求值项可表示一个一般的未求值的表达式，而不仅是符号(@5.4.5.1) ，但构造延迟求值项需要较大的开销。
延迟构造项不出现在词法分析(@5.3.1) 阶段。
延迟求值项可作为值对象和其它项区分，影响一个项是否为范式(@5.5.4.3) 。

@5.4.5.3 项引用：
TermReference 储存在 Value 中引用一个项。
用于在必要时引用一个项，但不在 TermNode 中直接储存这个项的值。
对实现作为一等对象(@4.1) 的列表(@5.4.4) 的引用(@4.1.4.1) ，支持引用整个项的中间值是必要的；但 TermReference 也支持引用非列表项。
对 TermReference 相关操作包括以下 API ：
NPL::ReferenceTerm 访问项并取解析 TermReference 间接值后的引用。
NPL::AccessTerm 和 YSLib::Access 访问 TermNode 类似，但先解析引用重定向到目标。
NPL::AccessTermPtr 和 YSLib::AccessPtr 访问 TermNode 类似，但先解析引用重定向到目标。

@5.4.5.4 其它中间值：
直接储存于 Value 的处理器(@5.5.8.1) 是中间值。
扩展中间值是其它由派生实现定义的中间值。

@5.4.6 值所有权：
项对 Value 数据成员具有所有权。项作为对象的所有权规则符合 @5.2.2 ，其余由派生实现指定。
值对宿主对象的所有权的机制由 Value 数据成员（具有 ValueObject 类型）相关的 API 提供。
默认使用的 ValueObject 使用值的持有者 YSLib::ValueHolder ，直接作为对象的表示，同时具有对象的所有权。
使用其它持有者或约定特定的中间值(@5.4.5) 实现间接值(indirect value) 允许和所有权分离的其它形式的表示，提供和非间接值不同的对象所有权和附加操作。
间接值具有访问被引用对象的 API ，并确保允许复制或转移引用的对象以恢复对应的非间接值。
间接值可用于代替非间接值，避免求值时改变环境(@5.4.3) 所有的非临时对象(@5.2.2) 的所有权。
间接值可实现和 C++ 引用类型表达式类似的行为。
NPLA 提供引入间接值的 API ，参见 @5.5.5.2 。
实现通过 Value 数据成员以外的机制也可隐含固定（不通过用户代码修改定制）的所有权关系，如上下文和环境(@5.4.3) 。
所有权机制和中间值(@5.4.5) 正交：具有间接值的对象可能作为中间值，也可能不作为中间值。

@5.4.6.1 引用持有者：
使用持有者 YSLib::RefHolder 的实例可实现间接值。

@5.4.6.2 引用值：
使用 TermReference(@5.4.5.4) 作为间接值引用一个项。

@5.5 NPLA 公共接口：
部分实现的功能由公共 API 的形式提供，以便派生实现复用。

@5.5.1 节点(node) 操作：
NPLA1 基于 ValueNode 提供了 TermNode 类(@5.4.2) 和 ContextNode 类(@5.4.3) 的操作的公共实现。
ContextNode 作为上下文的实现，其中包含的部分数据成员是环境(@4.6.1.1) 的实现。
尽管暂时未依赖节点性质，当前环境对象的类型和 TermNode 相同，也是 ValueNode 的别名。这里的类型等价性是实现细节，不应被用户代码依赖。

@5.5.1.1 项节点结构分类：
节点容器的内容被视为子节点按迭代顺序确定的有限的序列，即真列表(proper list) 。
真列表不包含环(cycle) 。其它形式的列表，如 Scheme 和 Kernel 中可能有环的非真列表(improper list) 不被支持。
按内容的结构，项节点具有如下互斥的基本分类（使用 TermNode 的 empty() 判断）：
枝节点(branch node) 或非叶节点，即具有子节点的非空列表节点；
叶节点(leaf node) ，即不具有子节点的空列表节点，或非列表节点。
若叶节点的 Value 数据成员为空（即 TermNode 显式转换为 bool 为 false 及 operator! 结果为 true ），则此节点是空节点。
列表节点(list node) 是枝节点或空节点。
可按照子节点数（使用 TermNode 的 size() 结果判断）进行扩展的扩展分类。
判断项节点基本分类的 API 在模块 NPL::SContext 提供：使用 IsBranch 、 IsEmpty 、 IsLeaf 和 IsList 分别判断是否为枝节点、空节点、叶节点和列表节点。
考虑 TermNode 的 Value 数据成员是否为空及其实际持有对象的动态类型等，具体实现 API 可约定使用不同的具体结构分类。
因为次级分类不一定是互斥的，所以可能需要约定对节点的操作顺序以确保结果一致，典型地可能有以下几种情形：
先判断是否为枝节点，再判断是否为符合预期类型的非空叶节点，分派不同的操作；
忽略子项使用项的值，不考虑子节点而只考虑 Value 数据成员；
使用子项和项的值进行操作，同时考虑子节点和 Value 数据成员。

@5.5.1.A 非规约节点操作：
部分 API 用于不经过规约过程的变换，为纯语法操作。
SXML(@5.8) 依赖这些 API 。
其它操作包括向输出流打印节点的文本表示等。

@5.5.2 异常处理：
NPL::NPLException 是 NPL 实现的异常基类。
其它 NPL 异常都从此类派生。
除 @5.5.1.A 外， NPLA 实现可能抛出这些异常。
NPLA 实现可能抛出标准库异常。

@5.5.3 上下文无关非节点处理 API ：
NPLA 实现提供不依赖一般项规约逻辑(@5.5.4) 的公共 TermNode 操作 API 。
以下 API 处理和 TermNode 或其中的成员数据类型相关但和 ContextNode 无关的数据。

@5.5.3.1 记号类别支持：
NPL::LexemeCategory 表示 NPLA 支持的词素(@5.4.5.1) 类别。
NPL::CategorizeBasicLexeme 和 NPL::CategorizeLexeme 对词素分类。两者的区别在于是否把扩展字面量视为符号(@5.4.5.1) 。
NPL::IsNPLAExtendedLiteralPrefix 判断字符是否为 @5.2 约定的扩展字面量前缀。
NPL::IsNPLASymbol 判断字符串是否为 NPLA 支持的符号。

@5.5.3.2 记号值：
基本概念参见 @5.4.5.1 。
调用 NPL::TermToName 访问具有记号值的名称节点对应的字符串。

@5.5.4 规约 API ：
NPLA 规约 API 约定默认使用 TermNode 和 ContextNode 类型的引用作为参数类型，参数分别表示被规约的节点和使用的上下文(@4.6.1) 。
其它变体参见 @5.5.4.5 。
NPLA 约定列表表达式(@3.4.2.3) 子项需进行递归的树规约(@5.4.2) 。
由树规约的性质(@5.4.2) ，可假定求值不改变参数外部的项的有效性，不需要额外的检查。
ContextNode 可被递归地作为子项规约的参数，因此可以不使用其它参数。
其它兼容实现可能使用其它参数。
NPLA 提供描述一次规约调用操作结束后的状态的枚举 ReductionStatus 作为规约的返回类型。

@5.5.4.1 规约结果：
ReductionStatus::Clean 指定纯值规约：规约成功终止(@4.4.3) ，且不需要保留子项。
ReductionStatus::Retained 指定纯列表规约：规约成功终止(@4.4.3) ，但需要保留子项。
ReductionStatus::Retrying 指定重规约，即所在的列表表达式需要以相同的参数重新调用进行进一步规约。
除重规约外，取得其它规约结果时，被规约的项（ TermNode 对象）表示求值结果(@4.1) ；另见 @5.4.4 。
除非实现逻辑需要或另行约定，规约结果默认为 ReductionStatus::Clean 。
规约结果作为规约实现的状态，设计原理如下：
基于实现的可扩展性、可复用性、复杂性和性能，判断规约终止的谓词（范式判断谓词）不一定适合在单独的规约过程中指定。
引入可指定规约不终止的显式的重规约状态代替范式判断谓词应对这些问题，允许项在最终取得范式前附加可变状态，并优化范式判断(@5.5.4.3.1) 。
区分规约终止的不同情形能在一定程度上复用已有的列表节点(@5.5.1.1) ，避免规约时节点或其它数据结构的一些冗余创建。

@5.5.4.2 延迟求值项：
基本概念参见 @5.4.5.2 。
DelayedTerm 是使用 ystdex::derived_entity 包装 TermNode 的别名。

@5.5.4.3 规约迭代：
对项的一次规约可分解为若干个对这个项的部分规约的有序的迭代过程，每个过程称为一个遍(pass) ；另见 @5.5.7 。
一次规约中有且仅有最后一遍规约迭代终止(@5.5.4.1) ；重规约(@5.5.4.1) 或通过抛出异常退出的迭代是一遍非终止的迭代。
一次不异常退出的规约按规约结果总是对应纯值规约、纯列表规约或重规约(@5.5.4.1) 之一。
NPL::CheckNorm 指定视为范式的项并提取规约状态，详见 @5.5.4.4.1 。
NPL::CheckReducible 检查参数指定的规约结果是否可继续规约，详见 @5.5.4.3.1 。
NPL::CheckedReduceWith 循环规约直至不满足 NPL::CheckReducible 的判断结果。
TermNode 用于规约迭代的表示，可能通过规约得到范式(@4.4.3) 。

@5.5.4.3.1 范式判断：
基于范式的定义，一次终止的(@5.5.4.1) 规约迭代应对 TermNode 参数进行规范化(@4.4.3) 以得到范式。
NPLA 提供以下等价的方式判断规约迭代后是否在 TermNode 得到范式：
除非另行约定，可直接使用 NPL::CheckReducible 以规约结果(@5.5.4.1) 决定是否为可继续规约的非范式；
通过检查节点结构的谓词 IsBranch(@5.5.1.1) 等作为范式判断谓词进行判断；
其它派生实现指定的范式的判断方式。
以上等价性由特定的 NPLA 规则（如 @5.5.4.4.1 ）和规约实现机制保证。
因为只检查规约结果的值而不访问项，使用 NPL::CheckReducible 代替范式判断谓词(@5.5.4.1) 一般能优化性能。
基于上述等价性保证，上述等价方式中的范式判断谓词可蕴含 NPL::CheckReducible 的结果，必要时也可用范式判断谓词代替规约结果，详见 @5.5.4.4.2 。

@5.5.4.3.2 规范化规约(@4.4.3) 约定：
除非另行约定(@5.5.4.4.2) ，一次终止的规约迭代中若存在规范化规约，其发生的次数和时机未指定；一般在最后一遍或之前存在一次即可。
注意规范化规约可能有引起可观察行为(@4.1.3) 变化的副作用(@4.1) ，实现应保证规约行为可被预期。

@5.5.4.4 正规(regular) 表示：
结合 @5.4.4 ，被求值的项的正规表示和规约结果有如下关系：
纯值规约由被规约的项的数据成员 Value 直接保存规约得到的值；
纯列表规约由被规约的项的子项决定规约得到的值。
满足上述约定的表示(@5.4.4) 是正规表示。
项通过求值取得正规表示是得到范式的必要非充分条件；为取得范式，可能需要继续进行规范化规约(@4.4.3) 。

@5.5.4.4.1 规约表示基本性质：
除非另行约定， NPLA 实现应保证规约过程中出现的表示满足以下基本性质：
任一遍规约中，非正规表示应保证可被（此次规约中剩余的操作）安全忽略而不改变规约的语义。
规约表示基本性质允许在已知 TermNode 得到范式时通过直接判断项的节点结构(@5.5.1.1) 是否存在子项代替推断此次规约中之前的规约结果。
NPL::CheckNorm(@5.5.4.3) 通过范式节点结构提取规约结果，是这种方法的直接的实现。

@5.5.4.4.2 正规化(regularization) 操作：
一次规约后，被规约的项中的 Value 或子项仍然可保留其它状态而非范式；对表示求值的情况，也不是正规表示(@5.5.4.4) 。
因为规范化规约可能存在副作用(@5.5.4.3.2)， NPLA 约定求值得到正规表示的规范化规约在抽象机(@2.6) 的意义上总是被进行，称为正规化操作。
纯值规约的正规化操作对子项进行清理，即移除不需要保留(@5.5.4.1) 的子项。
若需避免子项的生存期扩展到所在的项，需确保存在可预期的清理操作。
因为子项的删除时机未指定(@5.4.2) ，不假定 NPLA 实现的规约清理求值后的节点，即清理由派生的具体规约实现指定。
一般在求值的最终返回规约结果(@5.5.4.1) 前，清理不需要保留的子项。
纯列表规约的规范化标记 Value 为特定的值，可以是默认构造的空值或派生实现定义的不表示表达式的值的记号值(@5.4.5.1) 。
注意正规化操作和之前的清理操作可能会影响项的生存期。
规约时保持当前使用的处理器的独占所有权([Documentation::CommonRules @@2.3.4.6]) 的项应具有足够长的生存期，以避免调用处理器时未定义行为。

@5.5.4.4.3 正规表示分类：
基于规约表示基本性质(@5.5.4.4.1) ，不需要单独判断正规表示。
基于正规化操作规则(@5.5.4.4.2) ，通过以下逻辑对作为表示(@5.4.4) 的 TermNode 分类：
具有非空子项的 TermNode 表示非空列表；
空节点表示空列表；
其它 TermNode 当 Value 数据成员不是特定的值时，表示非列表表达式的值。
注意 Value 数据成员为特定的值（如中间值(@5.4.5) ）的没有子项的 TermNode 不是任何表达式的表示。

@5.5.4.5 规约函数：
除了以上类型外的规约 API 主要以 C++ 函数的形式提供，称为规约函数。
规约函数以被规约的项作为起始形式参数，包括以下形式：
第一参数为被规约的项，类型为 TermNode& ；
或者，起始参数是和 TermNode& 等价的容器的以下至少之一：
	对 TermNode::Container 对象的左值引用或 TermNode::Container 对象上的连续序列的迭代器范围之一；
	表示 Value 数据成员的对 ValueObject 对象的左值引用。
替代 TermNode& 的参数的形式允许不构造完整的 TermNode 而提升性能，但仅在保证不要求直接使用 TermNode （如取得 O(1) 的 size() 或调用遍(@6.2.4) ）时适用。
规约函数的返回类型是 ReductionStatus 或 void 。
返回 void 的规约函数在规约结果(@5.5.4.1) 的语义上同总是返回 ReductionStatus::Clean 。
规约函数可以调用其它规约函数实现。注意因为可直接忽略被调用的规约函数的返回值并指定其它值，规约函数的实现的分类不一定具有组合性。

@5.5.4.5.1 直接规约函数：
一些规约函数被设计可直接用于作为 EvaluationPass(@5.5.7.2) 遍(@5.5.7) 处理器，称为直接规约函数。其余规约函数是间接规约函数。
直接规约函数对形式参数的使用应符合 NPLA 实现的规约迭代默认的约定(@5.5.4)，即一个必要非充分条件是：
第一参数的类型是 TermNode& ，且当第二参数存在时，其类型可转换为 ContextNode& 。

@5.5.5 上下文无关的项操作：
提供 API 辅助对项的操作，可用于实现规约函数。

@5.5.5.1 附加子项：
NPL::AppendTerm 在现有的项的子项后添加新的子项。

@5.5.5.2 提升项：
对项的提升(lifting) 值使用项进行一定的变换后取代其它项或其一部分。
被提升的项一般被转移，因此需要可修改。
提升时对抽象的值表示进行操作实现基本的语义功能，可能进行附加的检查。
NPL::LiftTerm 提升项：设置项的内容为参数指定的项或值。
NPL::LiftDelayed 以引用方式提升延迟求值项(@5.5.4.2) 。
NPL::LiftFirst 和 NPL::LiftLast 提升第一个和最后一个子项。
以下值操作可能引入间接值(@5.4.6) ：
NPL::LiftTermObject 提升项对象：设置作为项的 Value 数据成员(@5.4.4) 的值对象为参数指定的值或值的引用值。
NPL::LiftTermOrRef 提升项或创建引用项。
NPL::LiftTermRef 提升项引用：提升项的内容为参数指定的项或值的引用值。引用值通过参数指定的值对象(@5.4.2) 上创建得到。
NPL::LiftToReference 提升项对象为引用。对 ValueObject 进行基于所有权的生存期检查并取表示其引用的间接值。
运行时进行的检查类似于强制 C++ 的一元 & 对表达式值类别(value category) 的要求但更严格（尽管仍然不能保证避免未定义行为），避免临时对象(@5.2.2) 被保存为引用值。另见 @6.2.7 。
NPL::LiftToSelf 递归提升项及其子项或递归创建项和子项对应的包含间接值的引用项到自身。
NPL::LiftToOther 递归提升项其子项或递归创建项和子项对应的包含间接值的引用项到其它项。调用 NPL::LiftToSelf 后再调用 NPL::LiftTerm 提升到其它项。

@5.5.6 辅助规约函数：
NPLA 提供只依赖项既有结构的项简单规约操作。这些操作不依赖上下文的 API ，可作为辅助规约函数。
NPL::ReduceHeadEmptyList 若项具有不少于一个子项且第一个子项是空列表则移除。
NPL::ReduceToList 对枝节点移除第一个子项，剩余项作为列表的元素，并返回 ReductionStatus::Retained(@5.5.4.1) ；否则返回 ReductionStatus::Clean(@5.5.4.1) 。返回值总是指示范式(@5.5.4.3.1) 。

@5.5.7 遍迭代 API ：
NPLA 实现提供基于 YSLib 事件（ YSLib::GEvent 的实例）的可调用的遍的集合作为一次规约迭代的基础可配置的边界。
每一遍规约迭代(@5.5.4.3) 实现为一个事件处理器。这允许运行时修改求值执行的不同逻辑以取得较大的灵活性和可扩展性。
NPL::ContextHandler(@5.5.1) 可作为 NPL::EvaluationPasses(@5.5.7.2) 的事件处理器。
部分遍以 ContextNode(@5.4.3) 的引用作为参数。声明时， ContextNode 不需要是完整类型。

@5.5.7.1 遍合并器：
多个遍的调用结果被遍合并器 NPL::PassesCombiner 定义的逻辑合并。（注意这不同于函数合并(@4.5.3) 。）
遍合并器依次调用事件处理器，合并调用的结果为表示是否需要重规约的值。
当发现调用的结果对应遍的规约结果需要重规约时，调用停止。
NPL::GPasses 是用于作为可合并结果的遍的泛型类型。从事件处理器合并的结果被作为调用结果。

@5.5.7.2 合并遍：
基于 NPL::GPasses ， NPLA 提供处理不同的种类的合并结果的遍：
NPL::TermPasses ：项合并遍，处理一般项的合并。项合并遍只使用项作为输入。
NPL::EvaluationPasses ：求值合并遍，处理一般求值的合并。求值使用项和上下文作为输入。
NPL::LiteralPasses ：字面量合并遍，处理已知为字面量的项的求值。

@5.5.7.3 非合并遍：
直接基于 YSLib::GEvent ， NPLA 还提供以下不合并结果的遍：
NPL::GuardPasses ：作用域守护遍，处理固定出口逻辑的遍，对应作用域守护类型 NPL::Guard 。最后一个作用域守护的值被作为调用的结果。

@5.5.8 环境和上下文处理：
类 ContextNode 表示上下文(@5.4.3) 。
只使用其中包含的环境时，可使用 ContextNode 和 Environment 的 API 访问环境的数据。
需要上下文时，可使用现有上下文，或通过现有上下文和环境创建新的上下文。

@5.5.8.1 处理器(handler) ：
基于使用 ContextNode 作为输入的事件处理器（ YSLib::GHEvent 的实例），可以组合不同的操作，用于实现规约(@5.5.4) 。
NPL::ContextHandler 以 TermNode 和 ContextNode 作为输入，实现一般的上下文处理。
NPL::LiteralHandler 以不可修改的 ContextNode 作为输入，用于和当前被规约的特定项无关的事件，典型地用于处理字面量引发特定的事件。
NPL::RegisterContextHandler 和 NPL::RegisterLiteralHandler 用于设置 ContextNode 子节点为对应的处理器。

@5.5.8.2 一般环境和上下文操作：
NPL::LookupName 用于在绑定集合中查找（一般作为局部变量的）标识符指定的名称，实现名称查找(@4.3.3) 。输入字符串指定（假定名称验证已通过的）名称。
NPL::FetchValue 分别用于在上下文中查找标识符指定的名称及取上下文中名称指称的值，实现对名称表达式(@4.5.1) 的求值。
NPL::FetchValuePtr 同 NPL::FetchValue 但不复制值。
NPL::DefineValue 、NPL::RedefineValue 和 NPL::RemoveIdentifier 修改上下文中的值。

@5.5.8.3 遍调用：
通过 NPL::InvokePasses ，在 ContextNode 上访问指定名称的子节点(@5.5.1) ，提取其中的值作为遍并调用。具体的名称和实现相关，非公开接口。

@5.6 NPLA1 约定：
NPLA1 仅使用宿主语言的类型和值作为状态。类型等价性基于类型映射(@5.2.1) 及其实现(@5.4.1) ，由 C++ 的语义规则定义。值等价性由宿主实现的 == 表达式的结果定义。
当前不特别约定类型系统，所有类型都是同宿主类型的空字符结尾的字符串（ C++ NTCTS ）。

@5.6.1 附加规则：
当前仅支持标识符(@3.3.1) 作为名称。
含有“$$”的名称保留给宿主交互使用；含有“__”的名称保留给 NPLA1 实现。
在 NPLA 规则(@5.2) 的基础上，具有以下情形的程序引起未定义行为：
显式使用保留给实现的标识符。

@5.7 NPLA1 应用实例：
NPLA1 当前加入特定的序列化和反序列化作为配置文件，参见 NPL::Configuration 。
NPLA1 的上述配置文件加入特定的匹配和初始化机制作为 YSLib::UI::Loader([Documenatation::YSLib @@5.8.8]) 在运行时读取用户界面布局和配置的脚本。
NPLA1 用于 MIME 类型和文件名映射([Documentation::YSLib @@4.5.3]) 的实现，上述配置文件对应的外部配置格式。
注意这些应用不直接使用 NPLA1 的语义，其中使用的 TermNode 类型中名称直接表示上下文(@4.6.1) 中的实体名称。
计划使用完整的实现(@6) 取代这些应用的底层，使用 NPLA1 作为对象语言或作为附加的代码生成遍重新实现这些应用，但具体路线图未定。另见 @6.7 和 @7.4 。

@5.8 NPLA 其它实现应用实例：
NPL::SXML 命名空间提供的 API 部分支持以 NPLA 分析 SXML 及构造 NPLA 表示的节点并转换为 XML 输出。
NPL 自定义分析器被用于 NPL::Dependency 模块中的函数 NPL::DecomposeMakefileDepList 实现解析 GCC 输出的兼容 GNU make 包含依赖字符串。

@5.9 兼容性：
除非在此另行约定， YSLib 中的 NPL 实现保持兼容。
影响向前兼容的变更：
b449 增加对多个未命名节点（叶节点或第一个子节点未能解析为名称的分支节点）作为非名称子节点时的反序列化支持。多个值会被以 $ 前缀接序号（从 0 起始）命名。之前的版本中读取的节点名称为空串，值被覆盖为第一个节点值。

@6 NPLA1 解释实现：
本章以 @5.3 约定的限定名称的方式使用 API 中出现的 C++ 名称。
NPL::TransformNPLA1 通过 ValueNode 变换实现解释，参数指定映射例程，结果为 NPL 序列语义结构。
复合表达式中的经过节点到字符串的映射例程被解释为序列语义结构的名称，余下的项一一映射为子节点。
变体 NPL::TransformNPLA1Sequence 使用 NodeSequence 代替 ValueNode::Container 作为结果中子节点的容器，其它行为和 NPL::TransformNPLA1 相同。
命名空间 NPL::A1 提供了特定于 NPLA1 的 API 。以下命名空间 A1 指 NPL::A1 。
命名空间 A1::Forms 提供了 NPLA1 的语法形式(@3.4.4) 对应的功能的实现(@6.6) 。
过程默认实现为子例程(@4.5.2.1) ，参见 @6.6.6 ；引入过程的具体形式可约定其它方式。

@6.1 节点记号：
NPLA1 实现使用 A1::ValueToken 枚举类型表示用于特殊标记的扩展中间值(@5.4.5.4) 。当前被保留未直接在规约例程(@6.2) 中使用。
A1::ValueToken::Null 用于作为规约(@6.2) 过程中 Value 数据成员的占位符，适合 Value 逻辑上为空但不符合其它要求（如需要保留节点但稍后规约中被移除）时的场合，当前实现对 NPLA1 实现都是透明的；
A1::ValueToken::Unspecified 用于表示未指定的值。语言规范可能使用未指定值，但实现的 API （如 A1::Forms(@6.6) ）会明确指定使用这个值（如设置这个值作为对象语言中函数的返回值），用户代码仍然不应依赖此处使用的具体值。
注意当前 A1::Reduce 规约时不对空节点（表示空列表）和 A1::ValueToken 类型的值进行操作。

@6.2 规约实现：
NPLA1 在 NPL::A1 中提供不同粒度的规约和求值实现 API 。

@6.2.1 规约函数约定：
基本约定参见 @5.5.4.5 。
以下规约函数的名称以 Reduce 起始：
直接规约函数(@5.5.4.5.1) ；
起始两个形式参数符合直接规约函数要求，且可能直接或间接调用其它直接规约函数的间接规约函数。
不调用其它直接规约函数的间接规约函数的名称以 Evaluate 起始。
其余规约函数的名称不以 Reduce 或 Evaluate 起始。

@6.2.2 主规约函数：
NPLA1 实现了一般的规约(@4.1) ，包括对列表表达式子项的递归规约。
主规约函数是直接规约函数(@5.5.4.5.1) 。
NPLA1 规约以 A1::Reduce 作为参考实现，返回类型为描述一次规约调用操作结束后的状态的 ReductionStatus(@5.5.4.1) 。
A1::Reduce 对参数中 TermNode 表示的表达式语法意义(@3.4.2) 上非空，但没有实现限制（即不附加检查）。
A1::Reduce 循环调用遍(@6.2.4) 进行必要的重规约，即迭代规约；通过 NPL::CheckReducible(@5.5.4.3) 判断是否需要重规约。
A1::Reduce 的实现中不直接指定需要重规约；所有 ReductionStatus::Retrying 都来自遍(@6.2.4) 的调用。
名称表达式的求值不进行进一步规约(@4.5.1) ，这由具体遍(@6.2.4) 的实现保证。关于记号，另见 @5.4.5.1 。
使用设置遍的 API(@6.2.4) 修改 ContextNode 中的具体遍以使用不同的规约规则。
基于 A1::Reduce 包装的辅助规约例程参见 @6.2.6 。

@6.2.3 迭代顺序：
A1::Reduce 定义节点次级结构分类(@5.5.1.1) 指定的规约迭代顺序被作为默认规约迭代顺序。
具体的分类和适用范围详见源代码文档。

@6.2.4 遍：
基于 NPLA 公共实现， NPLA1 使用以下的供迭代的遍(@5.5.7) ：
守护遍(guard pass) ，类型是一个 GuardPasses(@5.5.7.3) ，用于提供调试回调等。
叶遍(leaf pass) ，类型是一个 EvaluationPasses(@5.5.7.2) ，用于实现叶节点(@5.5.1.1) 对应表达式的求值。
列表遍(list pass) ，类型是一个 EvaluationPasses ，用于实现列表节点对应表达式的求值。
字面量遍(literal pass) ，类型是附加 string_view 参数的 EvaluationPasses ，用于在列表遍的处理器内部调用，处理不同类型的字面量。
NPLA1 可配置的遍保存在 ContextNode 中，其名称为保留标识符(@5.6.1) 。
字面量遍的处理器应翻译可接受的字面量，返回结果为 ReductionStatus::Clean ；否则，返回 ReductionStatus::Retrying 。后者包括标识符是符号(@5.4.5.1) 的情形。

@6.2.4.1 遍访问器(accessor) ：
通过以下 API 从 ContextNode 的指定子节点中取遍的可修改的引用：
A1::AccessGuardPassesRef 访问守护遍。
A1::AccessLeafPassesRef 访问叶遍。
A1::AccessListPassesRef 访问列表遍。
A1::AccessLiteralPassesRef 访问字面量遍。

@6.2.4.2 调用：
通过以下基于 NPL::InvokePass(@5.5.8.3) 的 API 以 ContextNode 的指定子节点内容作为遍并调用：
A1::InvokeGuard 调用守护遍。
A1::InvokeLeaf 调用叶遍。
A1::InvokeList 调用列表遍。
A1::InvokeLiteral 调用字面量遍。

@6.2.4.3 遍规约约定：
A1::Reduce(@6.2.2) 满足迭代顺序(@6.2.3) 提供的保证优先检查子节点数，列表遍仅用于子节点数大于 1 的非叶节点(@5.5.1.1) 求值。
这个特性允许在确定被求值的子项添加匹配的括号而不改变语义，且在列表遍中可简化子项求值（如 @6.4.5 直接 ReduceCombined(@6.4.5.1) 而不需检查节点数量是否大于 1 ）。
一般列表遍不依赖以上假设，可能对叶节点或具有一个节点的平凡列表节点对应的表达式求值。因此列表遍不是枝节点(@5.5.1.1) 遍。
遍的调用不一定需要维护共享状态，也因此一般多个遍被调用时不保证求值的强异常安全。
除 A1::ReduceCombined(@6.4.5) ， NPLA1 规约实现不保证进行正规化操作(@5.5.4.4.2) ；实现列表遍的用户代码需注意清理不需要的子项。

@6.2.6 辅助规约函数：
辅助规约函数可直接或间接地实现遍规约。
和 A1::Reduce(@6.2.2) 类似，辅助规约函数能处理一般情形的项，不存在作为断言的前置条件要求项非空。
A1::ReduceArguments 从第二个子项起逐项规约。
A1::ReduceArguments 允许单一子项表示没有参数的情形，即便这不会通过 A1::Reduce(@6.2.2) 得到（因为子节点数为 1 时不调用列表遍），也可简化某些实现如 @6.6.6 。
A1::ReduceChecked 循环规约直至 NPL::CheckReducible 判断不可继续规约；注意这可能引起迭代无法退出，不保证强规范化性质。
A1::ReduceCheckedClosure 规约并传递闭包调用的结果。闭包规约的结果（过程的返回值）以调用 ValueObject::MakeMoveCopy 初始化 TermNode::ValueObject 的形式传递，避免引用局部对象的超出生存期的引用传递到调用外部，维护内存安全。
A1::ReduceChildren 规约子项。
A1::ReduceFirst 对可能存在的第一个子项进行规约。
若第一个子项规约结果可被作为列表求值遍的事件处理器，整个项可继续规约。能进行此规约的形式称为 fexpr ，其中 f 表示 first 。
在某些其它语言中，符合类似求值规则的构造也称为 fexpr ，但语源不尽相同。
可组合使用 fexpr 的求值以及其它显式对 fexpr 子表达式的求值实现非严格求值(@4.4.4.5) 。
因为避免判断未指定子表达式是否需要规约（实现即非确定性求值(@4.4.4.5) ）， A1::ReduceFirst 一般具有较小的解释开销。
A1::ReduceOrdered 移除第一个子项并顺序规约余下的子项，使用最后一个子项的值。
A1::ReduceTail 移除第一个子项并规约余下的项。
A1::SetupTraceDepth 设置跟踪深度节点，主要用于调试。

@6.2.7 被规约项：
在 NPLA 的一般约定(@5.2) 外， NPLA1 对规约实现中项的使用有如下附加说明和约定。
关于内存安全和临时对象的基本规则，参见 @5.2.2 。

@6.2.7.1 结构：
项的结构（如项的分类(@5.5.1.1) 或子项数）和检查密切相关(@6.4.1.1) 。
遍的处理可能改变项的结构。应注意避免遍的处理器实现因此被改变自身或对此具有所有权的对象生存期导致未定义行为。

@6.2.7.2 值类别(value category) ：
和 ISO C++17 （及提案 P0135R1 ）类似，表示表达式的项及在表达式规约中得到的项具有以下值类别之一：
泛左值(glvalue) ：求值用于标识对象同一性(identity) 的项；
纯右值(prvalue) ：求值用于初始化临时对象或计算求值结果的项。
一个项可能被标记为消亡值(xvalue) 或附加其它元数据，以提供基于不同的所有权的行为。
左值(lvalue) 是除了消亡值外的泛左值。
右值(rvalue) 是消亡值或纯右值。
求值涉及项的值类别仅在必要时约定。明确引用直接存储环境中的对象及其包含的（数据成员）子对象的项都是左值；其余项为纯右值。
泛左值总是允许作为纯右值使用，称为左值到右值转换(lvalue-to-rvalue conversion) 。
从纯右值初始化临时对象的过程称为临时对象化转换(temporary materialization conversion) 。
值类别根据是否只关心表达式关联的（对象的或非对象的）值，在需要对象时提供区分两类一等对象(@4.1.4) 的机制，同时避免在仅需要表达式关联的值时引入不必要的其它对象。

@6.2.7.3 项对象(term object) 所有权：
具有值类别的项若标识对象，对应的对象是这个项的项对象。项对象是求值结果或中间结果对应的对象。
项对象可能不直接由项自身表示，即可以通过项引用其它途径引入的对象。
基于 @5.4.6 ，为保证内存安全，避免临时对象被引用，仅在泛左值(@6.2.7.2) 中允许引入被可能引用的间接值。
推论：泛左值的项对象不是临时对象，被环境所有。
通常纯右值作为其它项的子项而被独占所有权，求值时可能通过临时对象化转换(@6.2.7.2) 标识创建的临时对象。
作为 @5.2.2 的实现，临时对象以项自身作为表示(@5.4.4) ，被纯右值所有，也间接被其它项所有。
未经临时对象化转换的临时对象在逻辑上不存在，但纯右值作为对象表示实现的子项和 Value 数据成员对象随纯右值在宿主语言中作为对象存在，允许互操作。
若互操作在纯右值的表示中创建宿主语言中的对象，也视为临时对象化转换。
特定情况下纯右值可能被环境所有，但应只通过复制等方式访问其值而不依赖所有权关系（如仅复制 TokenValue 值(@6.2.7.4.2) ）。

@6.2.7.4 间接值使用规则：
基于 @5.4.6 ，实现应在适当情形复制或转移可能被引用的间接值引用的对象以保证满足生存期要求(@6.2.7.5) ，维护内存安全。
不能满足上述适当情形条件的若没有明确产生错误，则行为未定义。

@6.2.7.4.1 引用：
由于左值(@6.2.7.2) 的项对象被环境所有(@6.2.7.3) ，在项上的求值需要其它项对象作为中间值。
这种中间值通过间接引用左值以确保左值标识的对象可作为一等对象(@4.1) 使用，也是一种间接值，称为引用(reference) 。
TermReference(@5.4.5.3) 类型作为左值的引用的内部表示。
并非所有对象需要引用，详见 @4.1.4.1 。
和 ISO C++ 类似， NPLA1 中引用不被继续引用，使用引用初始化引用会引用到被引用的对象(referent) 上，即引用折叠(collapse) 。
NPLA 没有直接对引用折叠提供支持，因此需在每处初始化 TermReference 前进行处理。
当前引入引用的情形仅包括 A1::EvaluateIdentifier(@5.5.5) 的调用。

@6.2.7.4.2 其它间接值：
规约实现在特定情形的求值中使用 NPL::LiftTermRef 等(@5.5.5.2) 引入间接值避免求值时改变泛左值(@6.2.7.2) 标识的非临时对象的所有权。
这些调用中只有空列表值和 TokenValue 类型的值被复制为非间接值，可以不是临时对象，表示待替换的符号(@5.4.5.1) ，可用于实现形式参数(@6.6.6) ；
否则，引入的间接值引用被环境所有的对象。
涉及引用(@6.2.7.4.1) 的求值时，使用 NPL::LiftTermOrRef(@5.5.5.2) 代替 NPL::LiftTermRef 的调用。
涉及被求值的引用的子项也需要是引用时，使用 NPL::LiftToSelf(@5.5.5.2) 代替。
注意不求值而仅替换项时，使用 NPL::LiftTerm 代替，这不引入间接值。
除构造间接值的例程(@5.5.5.2) ，当前引入间接值的情形仅包括 A1::EvaluateIdentifier(@5.5.5) 的调用；
对应复制或转移间接值在过程中返回替换项时实现(@6.6.6.4) 。

@6.2.7.5 生存期：
关于被求值的被规约项对象的所有权，另见 @6.2.7.3 ；关于对应的 API ，参见 @6.4.5 。
基本生存期规则：
被规约对象中间接值的生存期总是不超过被引用的环境中的对象，以保证内存安全。
由于存在正规化操作(@5.5.4.4.2) ，一般没有必要提前清理项。

@6.2.7.5.1 规约范式实现约束：
实现 WHNF(@4.4.3.1) 时，第一个子项是规约时保持处理器的独占所有权的项(@5.5.4.5.2) ；其它项没有特别限制，但仍应注意 @6.2.7 。
在无法预知子项是否需要被进一步使用而不会在被调用前另行存储包含处理器的项时，实现的处理器应避免删除这里的子项（对实现 WHNF 而言即第一个子项），以免无法使用其中的状态。
若需要调整项的结构以便使用特定 API ，可使用 TermNode& 作为参数的规约函数(@5.5.4.5) ；如不可行，一般需转移到新建的项上进行调用，以免改变现有的项导致无法使用处理器中的状态。
特别地，除了以下例外，一般应避免在被处理的 TermNode 上直接调用 RemoveHead 。
作为例外，主规约函数(@6.2.2) 和 @6.6 支持的函数的实现可假定被在调用处理器前会转移子项的处理器调用。
通过处理 WHNF 的调用遍处理器的 A1::ReduceCombined(@6.4.5.1) 在调用处理器前会转移子项，可保证调用时生存期不会因为直接清理第一个子项而结束。

@6.2.7.5.2 默认解释环境：
A1::SetupDefaultInterpretation(@6.5) 也支持 @6.2.7.5.1 中的假设，因此可在默认 REPL(@6.5) 中使用。

@6.2.8 中间值：
NPLA1 规约使用 @5.4.5 约定的类型影响求值状态，不引入其它类型的中间值。

@6.3 中缀变换：
NPLA1 提供把特定的中缀分隔符替换为特定名称表达式(@4.5.1) 指定的前缀操作形式的列表。
A1::TransformForSeparator 非递归变换。
A1::TransformForSeparatorRecursive 递归变换。
A1::ReplaceSeparatedChildren 查找项中的指定分隔符，若找到则替换项为去除分隔符并添加替换前缀的形式。
变换结果可被进一步规约。

@6.4 遍处理：
除主规约函数(@6.2.2) 和辅助规约函数(@6.2.4) 外， NPLA1 还提供若干 API 作为和特定节点内容相关的具有特定功能的遍(@6.2.4) 的事件处理器。
详细功能参见源代码文档。

@6.4.1 上下文处理器：
基于 NPL::ContextHandler(@5.5.8.1) ， NPLA1 提供了包含特定公共（检查或其它功能）逻辑的节点处理器包装其它事件处理器。
A1::WrappedContextHandler 模板是适配可选返回类型的包装模板。当处理器返回类型为 void 时，可默认指定返回值为 ReductionStatus::Clean(@5.5.4.1) 。
迭代时，求值遍(@5.5.4.1) 可选使用基于 NPL::ContextHandler 的处理器作为 NPL::EvaluationPasses 事件处理器：
A1::FormContextHandler ：形式上下文处理器，表示操作子(@4.5.3.2) 。
A1::StrictContextHandler ：严格形式上下文处理器，严格求值(@4.5.4) 的操作子(@4.5.3.2) 。
两者的数据成员 Handler 为被包装的处理器，类型分别为 NPL::ContextHandler 和 A1::FormContextHandler 。
A1::FormContextHandler::operator() 依次进行以下操作：
若 Check 数据成员非空则调用 Check 进行检查，失败时抛出异常；
调用被包装的处理器 Handler 数据成员。
A1::StrictContextHandler::operator() 依次进行以下操作：
调用 A1::ReduceArguments 求值每一个子项（函数参数）；
调用被包装的处理器 Handler 数据成员。
除此之外，两者的 operator() 的附加操作参见 @6.4.1.1 。
注意上下文处理器不只适用于特定的规约实现如 A1::Reduce(@6.2.2) 。
注意直接在处理器中调用规约实现可导致无限递归；另见 @4.4.3 。

@6.4.1.1 前置条件检查和异常处理：
A1::FormContextHandler 的数据成员 Check 指定调用包装处理器之前的项检查。
检查不存在或通过检查后， A1::FormContextHandler::operator() 调用被包装的处理器 Handler 数据成员，并处理部分异常。
Check 默认指定 IsBranch 作为调用的前置条件；也可以指定其它谓词。
为易于复用处理器逻辑，利用合适的检查例程保证调用的处理器的前置条件，而不依赖特定规约实现调用时使用对项的结构(@6.2.7.1) 等形式的假设。
一般仍然需要 IsBranch 或 Forms::RetainN(@6.6.1.2) 等实现 Check ，即使这些处理器在使用主规约函数(@6.2.2) 时仅被作为枝节点处理器。这样，对不基于主规约函数的其它规约实现也可以安全地复用。
被调用的处理器中内部也可以有检查，这和上下文处理器中的项检查互补。
因为调用 Check 检查后立即调用处理器，使用 Check 或在被调用的处理器内部检查可以等效。具体实现中一般考虑便于复用、避免重复检查和简化实现难度进行选择。
若被调用的处理器自行检查前置条件，则项检查可以不存在。项检查可不必在被包装的处理器中重复进行（可使用断言代替）。
NPLA1 实现中，作为被调用的处理器（如 @6.2.6 和 @6.6 中的 API ）中可能存在对参数数量的检查。这类检查中已对枝节点类别进行检查，即不需要指定 NPL::IsBranch 作为前置条件。

@6.4.1.2 比较操作：
包装模板和上下文处理器提供重载操作符 == 以支持比较谓词(@6.6.9) 。
比较是必要的；否则，实例化 GHEvent 的操作可能导致无限递归调用。
当前没有直接提供 != 和其它比较操作。

@6.4.2 助手函数模板：
类似 NPLA1 ，此处也提供了注册处理器事件的助手函数模板 A1::RegisterForm 和 A1::RegisterFunction 。
此外，还有允许重载的 A1::ToContextHandler 函数模板以简化实现。
助手函数的模板传入被包装的处理器和检查例程。

@6.4.3 项变换 API ：
对中缀变换(@6.3) ，提供 A1::RegisterSequenceContextTransformer 简化向 EvaluationPasses 添加事件处理器。

@6.4.4 项检查和辅助 API ：
A1::AssertBranch 断言项是枝节点。
A1::FetchArgumentN 返回子项作为函数时的实际参数数，即子项数减 1 。

@6.4.5 项求值 API ：
NPLA1 提供规约处理器若干 API 实现基于节点的表达式求值。
A1::EvaluateIdentifier 对标识符项求值，解析名称(@4.3.3) 并初始化目标项的值；然后检查字面量处理器，若存在则调用；最后调用 A1::EvaluateDelayed 。
A1::EvaluateLeafToken 对作为叶节点记号的项求值，其中会判断字面量并按需调用字面量合并遍(@5.5.7.2) 或 A1::EvaluateIdentifier 。
A1::EvaluateDelayed 对值对象为延迟求值项(@5.4.5.2) 的项继续规约，以配合先前求值表达式时不直接规约(@6.2) 而实现非严格求值(@4.4.4.5)。
A1::ReduceCombined 规约作为上下文列表的枝节点，详见 @6.4.5.1 。
A1::ReduceLeafToken 规约叶节点记号，提取名称并调用 A1::EvaluateLeafToken 求值对应项。
A1::EvaluateLeafToken 中对目标项的值的初始化实现引用折叠(@6.2.7.4.1) 。

@6.4.5.1 A1::ReduceCombined：
A1::ReduceCombined 对枝节点以已规约的第一个子项为上下文处理器(@6.4.1) 并返回调用结果，以节约严格性分析(@4.4.4.2) 开销；并根据处理器返回的规约结果进行正规化操作。
通过节点的 Value 是否为 ContextHandler 类型的值或引用到 ContextHandler 的值上的 TermReference 的值确定是否为上下文处理器。
若存在调用，且不是（表示左值的）引用的情形，则先从第一个子项转移 ContextHandler 对象，以维护生存期。
调用上下文传递时不清理参数，即处理器中的第一个子项是已被清理的项，可被实现使用。
当调用返回 ReductionStatus::Clean 时，在返回结果前清理(@5.5.4.4.2) 子项（另见 @6.2.4 ）。
当调用返回 ReductionStatus::Retained 时，在返回结果前设置值为 A1::ValueToken::Null(@6.1) 以标记空参数列表。
当枝节点的第一个子项不是上下文处理器时失败，抛出 ListReductionFailure 异常。
对叶节点直接返回 ReductionStatus::Clean ，无其它作用。
配合 A1::FormContextHandler 在第一个子项上提供中间值(@5.4.5) ，得到的项为 WHNF(@4.4.3.1) ； A1::ReduceCombined 实现 WHNF 的求值。

@6.4.6 环境和上下文处理 API ：
A1::ResolveName 解析名称：处理保留名称并查找名称(@4.3.3) 。
解析名称重定向上下文时，可能找到循环引用；作为 @5.2 的补充，此时抛出异常。
A1::ResolveEnvironment 解析环境：只支持要求作为一等对象(@4.1) 的环境引用(@5.4.3) 。

@6.5 REPL API ：
NPLA1 提供 REPL API 以便于组装 REPL 和解释器。
A1::SetupDefaultInterpretation 初始化默认解释，包括一般事件处理例程。
A1::REPLContext 类可直接作为 REPL 原型。

@6.6 语法形式对应功能的实现：
命名空间 A1::Forms 的 API 专用于实现语法形式对应的功能而不是 NPLA1 的一般机制。
这些功能对 NPLA1 实现并非严格地必要，但适合使用宿主语言实现，被 NPLA1 代码间接地调用。
因此，这些 API 不被 A1::Forms 以外的 API 及实现依赖。
这些 API 符合本节以下内容的约定。
除非另行约定，这些形式不是特殊形式(@5.2) ，一般作为按值传递(@4.4.4.5) 的函数(@4.5.2) ；其中的值对象(@5.4.1) 表示引用时，可传递引用。
以下 API 因为传递无所有权引用，应避免超出生存期使用，以保证内存安全(@5.2.2) ：
Forms::GetCurrentEnvironment(@6.6.10) 。
从 @6.6.2 起本节余下的 API 中的规约函数(@5.5.4.5) 具有间接断言：第一参数指定的项是枝节点。

@6.6.1 非上下文操作：
非上下文操作不依赖上下文，无 ContextNode(@5.4.3) 参数。

@6.6.1.1 记号操作：
Forms::IsSymbol 判断字符串值是否可构成符号。
Forms::StringToSymbol 创建等于指定字符串值的记号值。不检查值是否符合符号要求。若能构成符号，则名称为指定字符串。
Forms::SymbolToString 取符号对应的名称字符串。

@6.6.1.2 保留(retain) 操作：
保留形式是特殊形式，对项进行空求值(@4.4.2) 。
Forms::Retain 断言枝节点并返回返回 ReductionStatus::Retained(@5.5.4.1) 。
Forms::RetainN 断言枝节点并检查子项作为函数时的实际参数数(@6.4.4) 符合预期。
保留的项不一定被直接需要值的操作如 Forms::Lambda(@6.6.6) 支持，一般不在用户代码中直接使用。

@6.6.2 绑定构造(binding construct) ：
绑定构造通过引入新的绑定(@4.1) 修改求值环境(@4.6.1.1) 。
作为 TermNode ，操作数的表示具有树的构造，称为操作数树(operand tree) 。
Forms::BindParameter 匹配并绑定操作数到参数上。绑定的对象节点的值和子节点元素被复制。
Forms::MatchParameter 匹配操作数树。
对实际参数，匹配前调用 NPL::LiftToSelf(@) 以支持引用。不对形式参数对应的函数参数进行修改，所以不对形式参数进行处理。若形式参数可能由求值得到，需在匹配前另行处理。
数据结构和匹配算法类似 Kernel 语言中用于 $define! 和 $vau 等操作子(@4.5.3.2) 的机制，但是 NPL 不使用 cons 对(pair) 。
此外，提供以下 API 修改环境：
Forms::DefineLazy ；
Forms::DefineWithNoRecursion ；
Forms::DefineWithRecursion ；
Forms::Undefine 。

@6.6.3 分支和逻辑操作：
Forms::If 提供基本的条件判断形式。
Forms::And 和 Forms::Or 提供对子项非严格求值的逻辑与和逻辑或操作。

@6.6.4 修饰符(modifier) ：
修饰符不作为单独的形式。语法形式可能具有可选的修饰符表示不同的功能。若存在修饰符，它在项的第二个子项。

@6.6.5 调用助手：
通过提供包装上下文处理器注册(@6.4.2) 的 API ，简化需要的回调形式。
基于 A1::RegisterStrict(@6.4.2) 注册严格上下文处理器。
Forms::CallUnary 和 Forms::CallUnaryAs 访问节点并调用一元函数。
Forms::CallBinary 和 Forms::CallBinaryAs 访问节点并调用二元函数。
以 As 为后缀的版本使用模板参数指定节点转换的目标类型作为提供回调的参数类型；否则参数类型为 TermNode& 。
Forms::UnaryExpansion 、 Forms::UnaryAsExpansion 、 Forms::BinaryExpansion 和 Forms::BinaryAsExpansion 提供对应的扩展调用，允许回调省略没有使用的 ContextNode& 类型的参数。
Forms::RegisterStrictUnary 注册一元严格求值上下文处理器。

@6.6.6 过程抽象：
过程可使用 A1::FormContextHandler(@6.4) 实现。
提供 Forms::Lambda 支持 lambda 特殊形式创建以过程为基础的 λ 抽象(@4.5.2.2) 。
提供 Forms::Vau 和 Forms::VauWithEnvironment 支持更一般的 vau 抽象(@4.5.2.3) 。前者和 Kernel 语言的 $vau 操作合并子类似，而后者进一步支持指定静态环境。
Vau 抽象可包含的捕获静态环境的数据结构，以非公开类型的对象存储，进一步初始化处理器类型 NPL::ContextHandler(@5.5.1) 的值，被待规约的项或环境所有(@5.2.2) 。
Vau 抽象的应用以包含局部环境(@4.6.1.1.2) 的数据结构作为活动记录帧(@5.2.2) 。
绑定参数使用 BindParameter(@6.6.2) 对参数进行复制以实现参数的按值传递(@4.4.4.5) 。
λ 抽象可通过 vau 抽象实现，但由于简单和性能原因，直接提供 API 支持。

@6.6.6.1 捕获：
环境中的变量被隐含地捕获。
捕获通过调用时设置在初始化保存的父环境(@5.4.3) 指针实现。
由于使用 weak_ptr 实例保证有效性，无效的父环境访问会出错，但行为仍可预测。
被 A1::EvaluateIdentifier(@6.4.5) 求值的变量按引用捕获。
若修改被捕获的变量对应的对象，可引起调用过程的可观察行为的改变。

@6.6.6.2 内部数据所有权：
存储在 vau 抽象对象内的数据包括：
形式参数对象；
上下文原型；
捕获的静态环境；
作为过程实现的求值结构(evaluation structure) （对应表达式中可能被求值的函数体(function body) ）；
这些数据都是被共享的。
其中，作为父环境(@5.4.3) 的静态环境以 weak_ptr 实例保存，并附加 shared_ptr 实例以可选被 vau 抽象所有；其它数据都以 shared_ptr 保存，被 vau 抽象所有。
除可选的静态环境 shared_ptr 实例，所有指针数据在 vau 抽象对象的生存期内都保持非空。
形式参数树作为数据成员同 vau 抽象对象被项或环境所有，可能被不同值类别的表达式标识，但它作为表达式和子表达式时不被直接求值，且子表达式中的符号被复制而不是以间接值引用(@6.2.7.4.2) ，因此是纯右值(@6.2.7.3) 。

@6.6.6.3 参数匹配：
通过 vau 抽象引入的函数调用在求值时，以 TermNode 的项而不是 ValueObject 的值对象替换上下文中的形式参数(@4.5.2) 树，用于在调用时被操作数树(@6.6.2) 作为实际参数替换。
匹配参数通过调用绑定构造的 API(@6.6.2) 实现。
形式参数的项可能在构造 vau 抽象请需被求值，而绑定构造的 API 不对此进行修改，因此实现时需要单独调用 NPL::LiftToSelf(@5.5.5.2) 求值，同时可确保在被保存(@6.6.6.2) 前不再引用其它项对象而维护内存安全。

@6.6.6.4 过程调用：
在调用过程时，局部环境通过共享的原型创建。求值时在局部环境进行名称解析(@5.4.3) ，通过保存的 weak_ptr 实例对静态环境的所有权进行检查，若失败则抛出异常。
保存在静态环境以外的对象的引用不受到以上机制保护，需要对形式参数对象可包含的对象进行限制以保证被规约项的所有权要求(@6.2.7.3) 。
因此， vau 抽象初始化时对形式参数对象检查，确保其中的非列表项中只存在调用 NPL::LiftTermRef 后也不引入间接值的对象的值，即 TokenValue 类型的值。
替换求值结构后，替换后的求值结构被求值。求值结束后需转移或复制求值结果(@6.2.7.4.2) 以避免引用之后被清理(@5.5.4.4.2) 的值引入未定义行为。
规约通过 A1::ReduceCheckedClosure 实现。

@6.6.7 列表应用：
Forms::Apply 实现以列表为参数列表的函数应用。

@6.6.8 外部调用：
Forms::CallSystem 实现到 YFramework 提供的 usystem 函数的调用转发，用于调用外部命令。

@6.6.9 内建谓词：
内建比较例程 Forms::EqualReference 和 Forms::EqualValue 分别支持通过引用和值分别比较。两者的语义接近 Scheme RnRS 的 eq? 和 eqv? 。
基于 YSLib::GHEvent ，上下文处理器(@6.4.1) 对未支持 == 比较的函数对象提供默认的相等实现，相同类型的函数对象的值视为恒等。
若需改变行为，需补充 operator== 。

@6.6.10 环境和求值操作：
Forms::Eval 提供指定环境求值的接口。
Forms::EvaluateUnit 提供创建 REPL 新实例并求值的便利接口。
Forms::MakeEnvironment 创建以参数指定的环境列表(@5.4.3) 作为父环境的新环境。
Forms::GetCurrentEnvironment 取当前环境的引用。
Forms::ValueOf 求值标识符得到指称的实体。

@6.6.11 合并子类型转换操作：
Forms 提供以下合并子(@4.5.3.2) 之间的非规约函数(@5.5.4.5) 转换例程：
Forms::Wrap 包装合并子为应用子。
Forms::Wrap1 包装操作子为应用子。
Forms::Unwrap 从应用子中取操作子。
其中后两者会对类型进行检查，若不满足条件则会抛出异常。

@6.7 依赖管理模块：
模块 NPL::Dependency 基于 NPLA1 提供 SHBuild 使用的一些 API 。
其中，函数 LoadNPLContextForSHBuild 提供 SHBuild 初始 REPL 环境，其中支持：
字面量初始化，支持 #t 、 #f 和整数等字面量；
启用预处理的分号和逗号转换，分别为有序和无序求值的语法糖。
相关对象语言的相关接口参见 @7.4 。
NPL::Dependency 还提供其它一些供 SHBuild 间接调用的操作。

@7 一般实现导引：
以下命名空间使用同 @6 。

@7.1 程序实现：
程序是语言的派生。实现程序即在语言的基础上指定派生规则。
使用 REPL API(@6.5) 创建 REPL 实例用于实现解释器。
使用 A1::Forms 的成员(@6.6) 指定需要内建支持的语法形式。
一般在初始化时自行绑定初始环境的名称。
上述成员约定的参考调用文法中，函数即合并子(@4.5.3.2) 等名称参见 Revised Report on the Kernel Programming Language 的约定，但使用未指定值惰性(inert) 值，因此以 ! 结尾的函数可能返回 A1::ValueToken::Unspecified(@6.1) 外的其它值。
以下接口主要介绍和 Kernel 约定不同的设计。各节的通用约定不再在之后的各个接口单独说明。

@7.2 规约文法约定：
规约操作中项的约束以 <> 中的名称表示。

@7.2.1 元文法基本约定如下：
... ： Kleene 星号，重复之前修饰的项 0 次或多次。
+ ： 重复之前修饰的项 1 次或多次。

@7.2.2 实体元素文法约定：
表示实体的元素也用于表示名义(nominal) 类型检查。
部分实体从属于其它实体类型而构成子类型(subtyping) 关系；部分规约操作取得求值结果保证结果中的值可能具有的特定类型集合，这些类型也一并在以下描述中给出；其它情形不指定类型。
实体元素的文法约定如下：
<object> ：一般对象。
<list> ：列表。和 Scheme 及 Kernel 不同， NPLA 支持的列表都是真列表(@5.5.1.1) ，不存在环。因此对应的操作中，没有对环存在性的检查。
<bool> ：布尔值，值为 #t 或 #f 的集合。
<symbol> ：符号。
<expression> ：待求值的表达式。
<expressions> ：待求值的形式上为一个或多个表达式。求值时首先组合为单一表达式。可以是一个 <expression> 。使用 <expressions> 代替 <expression> 可避免过多的括号及 eval 形式中的 list 。
<binding> ：绑定列表，形式为 <symbol> <expressions> ，用于指定被求值的表达式和绑定目标的符号。和 Kernel 不同， <symbol> 后不要求是整个 <expression> 。
<bindings> ：元素为 <binding> 的非空列表。
<body> ：形式上为 <expressions>? ，出现在形式的末尾，用于函数体(@6.6.6) 等替换求值的目标。
<test> ：类似 <object> ，通常预期为 <bool> ，且和 Scheme 类似但和 Kenerl 不同，非 #t 的值视为 #f 。
<consequent> ：同 <expression> ，仅用于条件表达式条件为 #t 时。
<alternate> ：同 <expression> ，仅用于条件表达式条件不为 #t 时。
<definiend> ：被绑定项的目标，是包含符号的表达式。
<formals> ：形式参数形式，同 <definiend> 但允许派生实现定义更多检查。
<clauses> ：条件列表。每个条件的形式为 <test> <body> 。
<combiner> ：合并子。
<applicative> ：应用子。
<predicate> ：谓词，是用于计算二元判断结果的合并子。对谓词应用操作数的求值结果的值为 <bool> 的 <applicative> 。通常实现为纯求值(@4.4.2) 。
<environment> ：表示环境的宿主值(@5.4.3) 。
规约预期符合约束。若违反由项的值对应的动态类型(@5.4.4) 不匹配导致，则求值失败；否则，行为未指定。
名义不同相同的约束可能仅要求相同的检查，可用于区分特定的含义，便于被实现优化。
表达式形式的结果指表达式的求值结果(@4.1) 。
类似 Kernel ，谓词的名称使用 ? 结尾，用于修改的合并子的名称使用 ! 结尾。和 Kernel 不同，后者的结果的类型未指定。

@7.2.3 派生实现类型：
部分库中使用的特定类型的项如下：
<string> ：字符串。
<regex> ：正则表达式。
字符串以 string 类型表示，编码和表示要求同 YFramework 默认约定([Documentation::YFramework @@3.3.1]) 。
正则表达式以 std::regex 类型表示，实现保证可通过 string 初始化。

@7.3 绑定操作和函数应用约定：
和 Scheme 及 Kernel 不同，求值为函数合并的应用表达式(@4.5.3) 不需要括号。为支持没有操作数的函数应用，需约定其它表达式表达函数合并。
当复合表达式的第一个子项为空列表 () 时，直接求值为一个函数合并(@4.5.3) ，这通过 NPL::ReduceHeadEmptyList(@5.5.6) 实现。对没有操作数的情形，这是唯一被直接支持函数应用的语法；否则，求值的作用同移除第一个子项 () 后的剩余形式。
以下使用 ... 作为函数的操作数时，可支持没有操作数的应用。此情形下应用表达式仍需要前缀 () ，但不在以下规约文法中显式地表示。
除非另行约定，约束名称后的整数序数仅用于区分允许的同类约束项不同，无其它附加含义。
和 Kernel 不同，环境(@7.4.2.4) 和合并子(@7.4.2.5)操作及基于这些操作的一些派生操作(@7.4.3) 的操作数树(@6.6.2) 构造不检查其中的非列表项是否都为符号或 #ignore ；匹配时不检查符号重复；若形式参数中的符号重复，则绑定的目标未指定。
和 Scheme 及 Kernel 不同，递归绑定符号的能力被显式分离，且明确支持在操作数中同时递归绑定多个符号。
本节中以下行为可能会在之后的实现中改变。

@7.3.1 递归绑定：
若同时绑定的递归符号构成循环引用，则递归绑定的值都是中间值(@5.3.1.1) 而不产生错误。

@7.3.2 无尾调用优化支持：
由于实现 NPLA 的宿主语言(@5.2) 不明确支持 TCO（Tail Call Optimization ，尾调用优化），在实现时显式使用尾调用形式(tail call) 才能支持空间复杂度和规约调用的嵌套深度无关。
当前实现的规约（如 A1::Reduce(@6.2.2) ）直接递归规约子表达式，不要求尾调用形式。
此外，通过环境支持的名称解析(@5.4.3) 的实现没有对是否使用尾调用形式进行约束。实际上默认的名称解析不直接递归，但调用的重定向操作可能以非尾调用形式进行递归调用。
因为一般调用不支持尾调用优化，递归调用也不进行特别的尾递归优化，因此实现循环可控制结构的程序应注意避免无限递归。如以下 Kernel 程序
($define! (f g) (list ($lambda (x) (g (- x 1))) ($lambda (x) (f (- x 1)))))
对应 NPLA1 程序（设 - 是减法）
$defrec! (f g) (list ($lambda (x) (g (- x 1))) ($lambda (x) (f (- x 1))))
会导致未定义行为而不是不终止求值。

@7.3.3 重绑定(rebinding) ：
和 Scheme 类似，允许变量被重新绑定，但被重新绑定的变量替换的对象会直接失效。
若继续访问已被求值（经过名称解析）指称的失效对象，则超出生存期访问而引起未定义行为。
因为设计原则禁止无法避免的实现开销，这里没有检查而直接指定为无法满足保证所有权条件的未定义行为(@6.2.7.4.2) 。

@7.3.4 循环引用：
循环引用引起 NPLA 未定义行为(@5.2) 。
典型实现中，循环引用可引起资源泄漏(resource leak) ，如内存泄漏(memory leak) 。
例如默认环境下求值以下表达式：
$let ((nenv () make-environment)) $set! nenv self nenv
可引起被捕获的环境中存储的对象无法释放。

@7.4 NPL::Dependency 参考实现环境：
模块 NPL::Dependency 提供的初始 REPL 环境。
除非是语义蕴含的操作结果或另行约定，所有函数的返回值未指定。未指定的值可等于 inert(@7.4.1) 或其它值。
约定的接口参见以下各节。

@7.4.1 内置对象：
inert ：类似 Kernel 的 #inert 字面量，但不作为字面量而是普通对象，关联 ValueToken::Unspecified(@6.1) 而不具有单独的类型（因此也不需要定义 inert? 谓词）。

@7.4.2 基本操作：
因为设计原因，除了 inert? 外(@7.4.1) ，也不支持以下 Kernel 操作：
set-car!
set-cdr!
copy-es-immutable
ignore?
其中，因为 #ignore 只是符号，也不会指称具有单独的类型的值，因此和 inert? 类似不被支持。
其它没有包含在以下节中的操作可能会在之后的版本中被支持。

@7.4.2.1 等价谓词：
eqv? <object1> <object2> ：表示值等于关系的应用子。
和 Kernel 不同，不提供 equal? 。对函数或列表的比较结果未指定。

@7.4.2.2 控制：
$if <test> <consequent> <alternate> ：条件分支。
$if <test> <consequent> ：省略第三操作数的条件分支。
和 Kernel 不同而和 Scheme 类似，对非 #t 的条件都视为 #f ，且支持省略第三操作数。

@7.4.2.3 列表操作：
null? <object> ：判断空列表。和 Kernel 不同，谓词只支持一个操作数，下同。
cons <object> <list> ：构造列表。和 Kernel 不同， NPL 不支持列表中存在环，因此第二个操作数必须是列表，否则出错。

@7.4.2.4 环境：
() copy-environment ：递归复制当前环境。当前忽略父环境中的环境列表(@5.4.3) 。结果为新创建的环境，具有宿主值类型 shared_ptr<Environment> 。
make-environment <environment>... ：创建环境。和 Kernel 不同，除对象类型外，没有对列表和绑定的附加检查。结果为新创建的环境，具有宿主值类型 shared_ptr<Environment> 。
() get-current-environment ：取得当前环境。因为设计以及实现的原因，和 Kernel 不同，这在 NPLA1 中是基本操作。结果为当前环境，具有宿主值类型 weak_ptr<Environment> 。
weaken-environment <environment>... ：创建环境弱引用。要求操作数的宿主值类型(@5.4.3) 是 shared_ptr<Environment> ，结果的宿主类型 weak_ptr<Environment> 。因为 NPLA1 需要精确控制所有权而不依赖垃圾回收(@5.2) ，这可用于派生实现某些操作（如 $sequence(@7.4.3.1) 必要的）。
eval <expression> <environment> ：在动态环境中求值。
$deflazy! <definiend> <expressions> ：修改绑定，类似 Kernel 的 $define! 但不对操作数求值且不支持递归。
$def! <definiend> <expressions> ：修改绑定，类似 Kernel 的 $define! 但不支持递归。
$defrec! <definiend> <expressions> ：修改绑定，类似 Kernel 的 $define! 。

@7.4.2.5 合并子：
$lambda <formals> <body>： λ 抽象(@4.5.2.2) 。因为性能原因实现为基本操作，但可以从 vau 抽象派生。表达式项的用法和以下 vau 抽象类似。
$vau <formals> <eformal> <body>： vau 抽象(@4.5.2.3) 。和 Scheme 及 Kernel 不同， <body> 可以是多个项，而不在派生另外的版本支持顺序求值。
$vaue <environment> <formals> <eformal> <body>：和 $vau 类似，但支持额外的求值环境作为静态环境。
wrap <combiner> ：包装合并子为应用子。
unwrap <applicative> ：取应用子对应的操作子。
注意和 Kernel 不同， $vau 和 $vaue 当前仍不足以取代内置的一等操作子，因为不支持只能转移而不能复制的对象。传递这些对象作为操作数会引起构造失败的异常。

@7.4.3 派生操作：
剩余操作可以从基本操作派生实现，或依赖其它实现特定的互操作接口实现。

@7.4.3.1 基本派生操作：
一些操作可以派生，但因为性能等原因使用 NPLA1 API 直接实现。这些操作的派生实现同时在 NPL::Dependency 模块内被给出。
$lambda <formals> <body> ：参见 @7.4.2.5 。
$sequence <object>... ：顺序求值。
list <object>... ：创建列表。

@7.4.3.2 核心库函数：
$quote <expression> 引用。结果为未被求值的操作数表达式。
$set! <expression1> <formals> <expression2> ：修改指定环境的绑定，使用 $def! ；类似 Kernel 的 $set! ，但不支持递归。
$setrec! <expression1> <formals> <expression2> ：修改指定环境的绑定，使用 $defrec! ；类似 Kernel 的 $set! ，支持递归。
first <list> ：取列表第一个元素。类似传统 Lisp 及 Kernel 的 car 。命名和 SRFI-1 及 Clojure 等现代变体一致。
rest <list> ：取列表第一个元素以外的元素构成的列表。命名同上。
apply <applicative> <object> <environment> ：在指定环境中应用。
apply <applicative> <object> ：在对当前环境中应用。
list* <objects>+ <list> ：在列表前附加元素创建列表，类似 cons 但支持多个操作数。因为不需要如 Kernel 支持派生 $vau ，使用 apply 派生。
$cond <clauses>... ：条件选择。注意 <body> 形式和 Kernel 不同。
$defl! <variable> <formals> <body> ：绑定 λ 抽象，等价 $def! <variable> $lambda <formals> <body> 。
$defv! <variable> <formals> <eformal> <body> ：绑定 vau 抽象，等价 $def! <variable> $vau <formals> <eformal> <body> 。
$defw! <variable> <formals> <eformal> <body> ：绑定 wrap 的 vau 抽象，等价 $def! <variable> wrap ($vau <formals> <eformal> <body>) 。
first-null? <list> ：符合 first 和 null? 操作。
list-rest <list> ：复合 list 和 rest 操作。
accl <list> <predicate> <object> <applicative1> <applicative2> <applicative3> ：实现左结合的二元映射操作。对列表进行处理取得部分和，谓词成立时结果为参数指定的对象，否则继续递归调用。处理列表的操作通过应用子分别定义：抽象列表头、列表尾和部分和的合并操作。
accr <list> <predicate> <object> <applicative1> <applicative2> <applicative3> ：实现右结合的二元映射操作。操作方式同 accl 。
foldr1 <applicative> <object> <list> ：同 accr ，但指定谓词为 null? ，应用子分别为 first 和 rest 。同 SRFI-1 的 fold-right ，但只接受一个真列表。
list-concat <list1> <list2> ：取顺序连接的表。
append <list>... ：拼接列表。
map1 <applicative> <list> ：单列表映射操作，使用指定应用子对列表中每个参数进行调用，结果为调用结果的列表。任意两个调用之间的相对求值顺序未指定。同 Kernel 的 map ，但只接受一个真列表。
$let <bindings> <body> ：局部绑定求值。注意 <body> 形式和 Kernel 不同。
$let* <bindings> <body> ：顺序局部绑定求值。注意同上。
not? <object> ：逻辑非。和 Kernel 不同而和 Scheme 类似，视所有非 #f 的值为 #t 。
$when <test> <body> ：条件为 #t 时顺序求值。
$unless <test> <body> ：条件不为 #t 时顺序求值。
$and? <test>... ：逻辑与。短路求值。当前暂时使用 NPLA1 API 直接实现。
$or? <test>... ：逻辑或。短路求值。当前暂时使用 NPLA1 API 直接实现。
unfoldable? <list> ：判断参数是否可被映射。映射类似 Kernel map 操作可接受的列表参数。
map-reverse <applicative> <list>... ：映射并反转结果。映射类似 Kernel map 操作。
for-each-ltr <applicative> <list>... ：从左到右映射取副作用。类似 Kernel 的 for-each 但保证顺序。

@7.4.3.3 对象互操作：
ref <object> ：取引用。不保证内存安全(@5.2.2) 。

@7.4.3.4 环境：
bound? <symbol> ：判断指定符号是否被绑定。
$binds1? <expression> <symbol> ：判断指定符号是否在指定表达式求值后指称的环境中绑定。和 Kernel 中的 $binds? 类似但只支持判断一个符号。
value-of <object> ：若操作数是字符串，求值标识符得到指称的实体。

@7.4.3.4 字符串库：
++ <string>... ：字符串串接。
string-empty? <string> ：判断字符串是否为空。
string<- <string1> <string2> ：字符串赋值。
string-contains-ci? <string1> <string2> ：判断忽略大小写的字符串中前者是否包含后者。
symbol->string <symbol> ：转换符号为字符串。
string->symbol <string> ：转换字符串为符号。不检查值是否符合符号要求。
regex->string <string> ：创建字符串初始化的正则表达式。
regex-match? <string> <regex> ：在字符串中搜索正则表达式指定的模式串

@7.4.3.5 输入/输出库：
puts <string> ：调用 std::puts 输出字符串。

@7.4.3.6 互操作库：
env-get <string> ：取宿主环境的环境变量字符串。
env-empty? ：判断环境变量是否为空。
system <string> ：调用 std::system 调用外部命令。使用 YSLib::usystem 实现。

@7.4.3.5 SHBuild 互操作接口：
SHBuild_BaseTerminalHook_ ：内部对象，用于终端控制。
SHBuild_BuildGCH_existed_ <string> ：判断参数指定路径的预编译头文件是否存在。
SHBuild_BuildGCH_mkpdirp_ <string> ：在预编译头文件构建时按需创建参数指定的路径父目录。
SHBuild_EchoVar <string1> <string2> ：在终端输出变量及其值。
SHBuild_Install_HardLink <string> ：以参数为路径安装硬链接。
SHBuild_QuoteS_ <string> ：为字符串添加单引号，以允许在 Shell 代码中使用。
SHBuild_RaiseError_ <string> ：产生错误。
SHBuild_SDot_ <string> ：替换字符串的点为下划线。
SHBuild_TrimOptions_ <string> ：清理选项字符串的空白符。
SHBuild_EchoVar_N <string> ：在终端输出环境变量及其值。
SHBuild_BuildGCH <string> ：构建参数指定路径的预编译头文件。

*/
////

