专业化系统上的确定性规则程序:子句模型语义
1. 引言
在声明式计算范式(如逻辑编程和函数式编程)中,规范与特定的过程语义相关联,使得规范可被视为程序。然而,这些范式中从规范生成程序的范围受限,“规范即程序”的概念给实际程序综合带来了严重限制,难以形成从声明式规范合成命令式程序的完整理论。
等效转换(ET)范式旨在为程序综合提供通用基础,它将程序和规范的概念清晰分离。规范确定了感兴趣的问题集并赋予问题声明性含义,不预设特定的过程语义。寻找程序不仅包括规范转换,还包括寻找优秀算法,这通过逐步构建优先的非确定性重写规则(N - 规则)集来实现。
N - 规则程序的计算状态由一组确定子句表示,计算是通过连续应用N - 规则得到的状态序列。ET范式的计算本质上是非确定性的,目标确定子句、规则应用的目标原子和适用的N - 规则都是非确定性选择的。
为了在N - 规则和命令式语言之间架起桥梁,引入了确定性重写规则(D - 规则)。D - 规则通过指定目标原子的模式、规则适用性条件和替换原子的模式来描述确定子句的一步转换,D - 规则程序是D - 规则的序列。在ET范式的确定性计算模型中,状态是有序确定子句,规则应用的目标原子和适用的D - 规则在每个状态转换步骤根据其出现顺序确定性选择。
对于N - 规则和D - 规则,等效转换原则被用作计算正确性的充分条件,即如果计算中的每个状态转换都是保持意义的转换步骤,那么计算是正确的。这一条件将许多可能的正确程序与规范相关联,大大拓宽了寻找高效正确程序的可能性。
之前关于N - 规则语义的理论具有通用性,其根源在于专业化系统的概念。专业化系统是一个抽象的公理结构,用于构建(扩展)原子空间并定义其上的专业化操作。基于专业化系统,已经成功开发了(广义)确定子句的声明式语义、逻辑结构理论和N - 规则的过程语义。通过实例化专业化系统,这些理论可直接应用于许多具体的数据域。
2. D - 规则示例
2.1 内置原子、内置求值器和用户定义原子
在D - 规则系统中,一些原子(包括超逻辑原子)用于指定预定义操作,称为内置原子。内置原子由预定的内置求值器求值,如果求值成功,将产生一个替换作为结果。例如,等式原子
=(t, t′)
表示合一操作,如果
t
和
t′
可合一,求值成功,结果替换为它们的最一般合一子。
除内置原子外的原子被视为用户定义原子,它们是规则应用的目标原子,通过应用D - 规则进行确定子句转换来求值。常见的用户定义原子有
app(l, l′, l′′)
、
toSet(l, l′)
、
member(t, l)
和
occur(t, t′)
等,分别表示列表追加、列表去重、元素属于列表和项在项中出现等含义。
2.2 简单D - 规则
以下是两个用于重写
app
原子的D - 规则:
r1: app([], ∗Y, ∗Z) −→=(∗Y, ∗Z).
r2: app([∗a|∗X], ∗Y, ∗Z) −→=(∗Z, [∗a|∗W ]), app(∗X, ∗Y, ∗W ).
这两个规则的适用性由模式匹配确定。
r1
匹配第一个参数为空列表的
app
原子,
r2
匹配第一个参数为非空列表的
app
原子。应用规则时,目标
app
原子将被规则右侧指定的原子实例替换。
下面的表格展示了使用这两个规则和内置求值器进行确定子句转换的示例:
| 步骤 | 规则 | 确定子句 |
| ---- | ---- | ---- |
| | | ans(∗A) ←app([1, 2], [3], ∗A) |
| 1 | r2 | ans(∗A) ←=(∗A, [1|∗W 1]), app([2], [3], ∗W 1) |
| 2 | e | ans([1|∗W 1]) ←app([2], [3], ∗W 1) |
| 3 | r2 | ans([1|∗W 1]) ←=(∗W 1, [2|∗W 2]), app([], [3], ∗W 2) |
| 4 | e | ans([1, 2|∗W 2]) ←app([], [3], ∗W2) |
| 5 | r1 | ans([1, 2|∗W 2]) ←=([3], ∗W 2) |
| 6 | e | ans([1, 2, 3]) ← |
当确定子句体中的第一个原子是
app
原子时,使用
r1
或
r2
进行重写;当是等式原子时,使用内置求值器求值。最终,初始子句转换为单位子句
ans([1, 2, 3]) ←
,表示列表
[1, 2, 3]
是无条件的答案。
2.3 带有适用性条件的D - 规则
除了模式匹配,还可以指定适用性条件,使规则仅适用于更特定类别的目标原子。以下是用于重写
toSet
原子和
member
原子的D - 规则:
r3: toSet([], ∗Z) −→=(∗Z, []).
r4: toSet([∗a|∗X], ∗Z), {member(∗a, ∗X)} −→toSet(∗X, ∗Z).
r5: toSet([∗a|∗X], ∗Z) −→=(∗Z, [∗a|∗W ]),toSet(∗X, ∗W ).
r6: member(∗a, [∗a|∗X]) −→.
r7: member(∗a, [∗b|∗X]) −→member(∗a, ∗X).
规则
r4
有一个适用性条件
{member(∗a, ∗X)}
。当目标原子模式
toSet([∗a|∗X], ∗Z)
通过替换
θ
实例化为体原子时,会检查相应的实例化适用性条件
member(∗aθ, ∗Xθ)
。
下面的表格展示了使用这些规则进行确定子句转换的示例:
| 步骤 | 规则 | 确定子句 |
| ---- | ---- | ---- |
| | | ans(∗A) ←toSet([1, 2, 1], ∗A) |
| 1 | r4 | ans(∗A) ←toSet([2, 1], ∗A) |
| 2 | r5 | ans(∗A) ←=(∗A, [2|∗W 1]), toSet([1], ∗W 1) |
| 3 | e | ans([2|∗W 1]) ←toSet([1], ∗W 1) |
| 4 | r5 | ans([2|∗W 1]) ←=(∗W 1, [1|∗W 2]), toSet([], ∗W2) |
| 5 | e | ans([2, 1|∗W2]) ←toSet([], ∗W 2) |
| 6 | r3 | ans([2, 1|∗W2]) ←=(∗W2, []) |
| 7 | e | ans([2, 1]) ←[] |
为了检查
r4
是否适用于体原子
toSet([1, 2, 1], ∗A)
,会对实例化条件
member(1, [2, 1])
进行求值,如下表所示:
| 步骤 | 规则 | 确定子句 |
| ---- | ---- | ---- |
| | | toSet([2, 1], ∗A) ←member(1, [2, 1]) |
| 1 | r7 | toSet([2, 1], ∗A) ←member(1, [1]) |
| 2 | r6 | toSet([2, 1], ∗A) ←[] |
由于该转换以单位子句结束,表明求值成功,因此应用
r4
。在每个转换步骤中,规则是确定性选择的,按规则出现顺序逐个检查规则的适用性,仅选择第一个适用的规则。
2.4 带有递归适用性条件的D - 规则
编写带有递归适用性条件的D - 规则很常见。以下是用于重写
occur
原子的D - 规则:
r8: occur(∗a,∗a) −→.
r9: occur(∗a,[∗A|∗B]), {occur(∗a, ∗A)} −→.
r10: occur(∗a,[∗A|∗B]) −→occur(∗a,∗B).
规则
r9
在
ta
出现在
tA
中时移除
occur(ta, [tA|tB])
形式的原子。
下面的表格展示了使用这些规则进行确定子句转换的示例:
| 步骤 | 规则 | 确定子句 |
| ---- | ---- | ---- |
| | | ans ←occur(1, [[2, 1, 0], [5, 4, 3]]) |
| 1 | r9 | ans ←[] |
为了确定
r9
是否适用于体原子
occur(1, [[2, 1, 0], [5, 4, 3]])
,会检查条件
occur(1, [2, 1, 0])
,这会启动另一个转换序列。在确定
r9
是否适用于
occur(1, [2, 1, 0])
时,会递归检查条件
occur(1, 2)
。由于
r8
、
r9
和
r10
都不适用于
occur(1, 2)
,该转换失败,因此在相应步骤使用
r10
。
2.5 通过适用性条件传递值
评估适用性条件可能会产生一个替换,该替换会实例化体原子,从而实现值的传递。假设
calc
原子是一个双参数内置原子,以第一个参数为输入进行计算并将结果作为第二个参数输出;
cond
原子是一个单参数内置原子,用于测试其参数是否满足特定条件。考虑以下两个规则:
calcCond(∗x, ∗z), {calc(∗x, ∗y), cond(∗y)} −→=(∗z, ∗y)
calcCond(∗x, ∗z) −→=(∗z, ∗x).
给定目标原子
calcCond(tx, ∗z)
,为了转换该目标原子,会首先检查第一个规则的适用性。如果适用性条件
calc(tx, ∗y)
和
cond(∗y)
都满足,目标原子将被替换为
=(∗z, ∗y)
;否则,使用第二个规则将目标原子替换为
=(∗z, ∗x)
。
3. 通用状态转换语义框架
为了建立用于连续转换单个确定子句的程序类及其精确的过程语义,我们构建了一个通用的状态转换语义框架。这个框架将计算定义为一个状态序列,其中状态转换步骤的确定可能需要构建其他计算。
在这个框架中,状态转换的过程可以用以下 mermaid 流程图表示:
graph TD;
A[初始状态] --> B{选择目标原子};
B --> C{选择适用规则};
C -->|规则适用| D[应用规则进行状态转换];
D --> E{是否达到终止条件};
E -->|否| B;
E -->|是| F[终止状态];
C -->|无适用规则| G[计算失败];
具体步骤如下:
1.
选择目标原子
:从当前状态的有序确定子句中选择一个目标原子。
2.
选择适用规则
:按规则出现顺序逐个检查规则的适用性,找到第一个适用的规则。
3.
应用规则进行状态转换
:如果找到适用规则,应用该规则对目标原子进行转换,得到新的状态。
4.
检查终止条件
:判断新的状态是否满足终止条件。如果不满足,返回步骤 1 继续进行状态转换;如果满足,计算结束。
5.
计算失败
:如果没有找到适用规则,计算失败。
4. 专业化系统上的 D - 规则程序建模
将 D - 规则程序在专业化系统上形式化为状态转换过程。专业化系统是一个抽象的公理结构,用于定义(扩展)原子空间和其上的专业化操作。
在专业化系统中,D - 规则程序的状态是一个有序确定子句,目标原子和适用规则的选择是根据它们的出现顺序确定性进行的。通过将专业化系统作为参数,D - 规则程序的理论可以应用于许多具体的数据域。
5. D - 规则程序过程语义的形式化
通过应用第 3 节的通用状态转换语义框架,对 D - 规则程序的过程语义进行形式化。
具体来说,对于一个 D - 规则程序,其过程语义可以通过以下步骤定义:
1.
初始状态
:将输入的确定子句作为初始状态。
2.
状态转换
:按照通用状态转换语义框架中的步骤,依次选择目标原子、适用规则,并应用规则进行状态转换。
3.
终止条件
:当状态满足终止条件(如达到单位子句)时,计算结束。
以下是一个简单的示例,展示了如何应用这个形式化的语义进行计算:
假设我们有以下 D - 规则程序:
r1: p(∗x) −→q(∗x).
r2: q(∗x) −→r(∗x).
初始确定子句为
ans ←p(a)
。
| 步骤 | 规则 | 确定子句 |
| ---- | ---- | ---- |
| | | ans ←p(a) |
| 1 | r1 | ans ←q(a) |
| 2 | r2 | ans ←r(a) |
通过这种方式,我们可以精确地定义 D - 规则程序的过程语义,为确定性程序综合提供了理论基础。
6. 总结
本文旨在建立用于连续转换单个确定子句的程序类及其精确的过程语义,重点研究了专业化系统上的确定性重写规则(D - 规则)程序。
通过引入 D - 规则,在非确定性重写规则(N - 规则)和命令式语言之间架起了桥梁。D - 规则通过指定目标原子模式、规则适用性条件和替换原子模式,实现了确定子句的一步转换。
我们构建了通用的状态转换语义框架,将 D - 规则程序形式化为状态转换过程,并对其过程语义进行了形式化。通过将专业化系统作为参数,这些理论可以应用于许多具体的数据域,为从声明式描述合成确定性程序提供了基础。
未来,我们可以进一步探索如何利用这些理论开发更高效的程序合成方法,以及如何将其应用于更多的实际场景中。
超级会员免费看
32

被折叠的 条评论
为什么被折叠?



