Recursion 用合金编程递归函数
我试图在Alloy中构造一个递归函数。根据丹尼尔·杰克逊书中的语法,这是可能的。我的职能是:Recursion 用合金编程递归函数,recursion,alloy,Recursion,Alloy,我试图在Alloy中构造一个递归函数。根据丹尼尔·杰克逊书中的语法,这是可能的。我的职能是: fun auxiliaryToAvoidCyclicRecursion[idTarget:MethodId, m:Method]: Method{ (m.b.id = idTarget) => { m } else (m.b.id != idTarget) => { (m.b = LiteralValue) => {
fun auxiliaryToAvoidCyclicRecursion[idTarget:MethodId, m:Method]: Method{
(m.b.id = idTarget) => {
m
} else (m.b.id != idTarget) => {
(m.b = LiteralValue) => {
m
} else {
some mRet:Method, c:Class | mRet in c.methods && m.b.id = mRet.id => auxiliaryToAvoidCyclicRecursion[idTarget, mRet]
}
}
}
但是解算器声称调用辅助避免循环错误[idTarget,mRet]
表示:
"This must be a formula expression.
Instead, it has the following possible type(s):
{this/Method}"
问题正是错误消息所说的:您的
auxiliaryToAvoidCyclicRecursion
函数的返回类型是Method
,您正试图在布尔蕴涵中使用它,其中的公式是预期的(即布尔类型)。在任何其他静态类型语言中都会出现同样的错误
您可以将函数重写为谓词来解决此问题:
pred auxiliaryToAvoidCyclicRecursion[idTarget:MethodId, m:Method, ans: Method] {
(m.b.id = idTarget) => {
ans = m
} else (m.b.id != idTarget) => {
(m.b = LiteralValue) => {
ans = m
} else {
some mRet:Method, c:Class {
(mRet in c.methods && m.b.id = mRet.id) =>
auxiliaryToAvoidCyclicRecursion[idTarget, mRet, ans]
}
}
}
}
这不会给您带来编译错误,但要运行它,请确保启用递归(选项->递归深度)。正如您将看到的,最大递归深度为3,这意味着Alloy Analyzer最多可以展开递归调用3次,而不管您的分析范围如何。当这还不够时,您仍然可以选择重写您的模型,以便将所讨论的递归谓词建模为关系。这里有一个简单的例子来说明这一点
具有递归定义的用于计算列表长度的函数的链表:
sig Node {
next: lone Node
} {
this !in this.^@next
}
fun len[n: Node]: Int {
(no n.next) => 1 else plus[1, len[n.next]]
}
// instance found when recursion depth is set to 3
run { some n: Node | len[n] > 3 } for 5 but 4 Int
// can't find an instance because of too few recursion unrollings (3),
// despite the scope being big enough
run { some n: Node | len[n] > 4 } for 5 but 4 Int
现在,将len
中的同一列表建模为一个关系(即节点中的字段
)
注意,后一种方法不使用递归(因此不依赖于“递归深度”配置选项的值),可以(通常是)明显比前者慢。问题正是错误消息所说的:您的
辅助AvoidCycleCrusion
函数的返回类型是方法
,您试图在布尔蕴涵中使用该方法,其中公式是预期的(即布尔类型)。在任何其他静态类型语言中都会出现同样的错误
您可以将函数重写为谓词来解决此问题:
pred auxiliaryToAvoidCyclicRecursion[idTarget:MethodId, m:Method, ans: Method] {
(m.b.id = idTarget) => {
ans = m
} else (m.b.id != idTarget) => {
(m.b = LiteralValue) => {
ans = m
} else {
some mRet:Method, c:Class {
(mRet in c.methods && m.b.id = mRet.id) =>
auxiliaryToAvoidCyclicRecursion[idTarget, mRet, ans]
}
}
}
}
这不会给您带来编译错误,但要运行它,请确保启用递归(选项->递归深度)。正如您将看到的,最大递归深度为3,这意味着Alloy Analyzer最多可以展开递归调用3次,而不管您的分析范围如何。当这还不够时,您仍然可以选择重写您的模型,以便将所讨论的递归谓词建模为关系。这里有一个简单的例子来说明这一点
具有递归定义的用于计算列表长度的函数的链表:
sig Node {
next: lone Node
} {
this !in this.^@next
}
fun len[n: Node]: Int {
(no n.next) => 1 else plus[1, len[n.next]]
}
// instance found when recursion depth is set to 3
run { some n: Node | len[n] > 3 } for 5 but 4 Int
// can't find an instance because of too few recursion unrollings (3),
// despite the scope being big enough
run { some n: Node | len[n] > 4 } for 5 but 4 Int
现在,将len
中的同一列表建模为一个关系(即节点中的字段
)
请注意,后一种方法不使用递归(因此不依赖于“递归深度”配置选项的值),可能(通常)比前一种方法慢得多。您应该发布模型的其余部分,以便我们可以运行它。您应该发布模型的其余部分,以便我们可以运行它。