有时,当我想在Alloy中使用递归时,我发现我可以使用传递闭包或序列。
例如,在无上下文语法模型中:
abstract sig Symbol {}
sig NT, T extends Symbol {}
// A grammar is a tuple(V, Sigma, Rules, Start)
one sig Grammar {
V : set NT,
Sigma : set T,
Rules : set Prod,
Start : one V
}
// A production rule has a left-hand side
// and a right-hand side
sig Prod {
lhs : NT,
rhs : seq Symbol
}
fact tidy_world {
// Don't fill the model with irrelevancies
Prod in Grammar.Rules
Symbol in (Grammar.V + Grammar.Sigma)
}
可达非终端的一种可能定义是"起始符号,以及出现在规则右侧的可达符号的任何非终端。"直接的翻译将是
// A non-terminal 'refers' to non-terminals
// in the right-hand sides of its rules
pred refers[n1, n2 : NT] {
let r = (Grammar.Rules & lhs.n1) |
n2 in r.rhs.elems
}
pred reachable[n : NT] {
n in Grammar.Start
or some n2 : NT
| (reachable[n2] and refers[n2,n])
}
可以预见,这会打击筹码。但是如果我们只是在refers
关系下(或严格来说,是由refers
谓词形成的关系)采用Grammar.Start的传递闭包,我们可以定义可达性:
// A non-terminal is 'reachable' if it's the
// start symbol or if it is referred to by
// (rules for) a reachable symbol.
pred Reachable[n : NT] {
n in Grammar.Start.*(
{n1, n2 : NT | refers[n1,n2]}
)
}
pred some_unreachable {
some n : (NT - Grammar.Start)
| not Reachable[n]
}
run some_unreachable for 4
原则上,生产符号的定义同样是递归的:符号是生产性的,如果它是终端符号,或者它至少有一个规则,其中右侧的每个符号都是有效的。写这个的简单方法是
pred productive[s : Symbol] {
s in T
or some p : (lhs.s) |
all r : (p.rhs.elems) | productive[r]
}
就像直接定义的可达性一样,这会打击堆栈。但我还没有找到一个我可以在符号上定义的关系,它将通过传递闭包给我我想要的结果。我是否发现了传递闭包不能代替递归的情况?或者我还没有想到找到正确的关系?
有一个明显的,如果费力的黑客:
pred p0[s : Symbol] { s in T }
pred p1[s : Symbol] { p0[s]
or some p : (lhs.s)
| all e : p.rhs.elems
| p0[e]}
pred p2[s : Symbol] { p1[s]
or some p : (lhs.s)
| all e : p.rhs.elems
| p1[e]}
pred p3[s : Symbol] { p2[s]
or some p : (lhs.s)
| all e : p.rhs.elems
| p2[e]}
... etc ...
pred productive[n : NT] {
p5[n]
}
只要不提出足够的谓词来处理最长可能的非终端引用链(如果提高范围),这就行了。
具体而言,我似乎有几个问题;我们欢迎他们回答任何问题:
1有没有办法在Alloy中定义一组生产性非终端而不诉诸p0,p1,p2,... hack?
2如果一个人必须诉诸黑客,是否有更好的方法来定义它?
3作为一个理论问题:是否有可能表征可以使用传递闭包或原子序列而不是递归来定义的递归谓词集?
答案 0 :(得分:1)
我是否发现了传递闭包无法替代递归的情况?
是的,就是这样。更准确地说,您发现了一个无法用一阶传递闭包表示的递归关系(在Alloy中支持)。
有没有办法在不使用p0,p1,p2,... hack的情况下在Alloy中定义生产性非终端的集合?如果一个人必须诉诸黑客,是否有更好的方法来定义它?
在Alloy中没有办法做到这一点。但是,可能有一种方法可以在支持高阶量化的Alloy*中执行此操作。 (我们的想法是描述生产要素的集合,其中包含关于"生产力"的关系,它将对生产符号集合使用二阶量化,并将该集合约束为最小。类似的想法在" A.1.9 Axiomatizing Transitive Closure"在Alloy书中描述。)
作为一个理论问题:是否有可能表征可以使用传递闭包或原子序列而不是递归来定义的递归谓词集?
这是一个有趣的问题。 wiki文章提到了在传递闭包和定点运算符被添加时(后者能够表达递归形式)的二阶逻辑的相对表达性。