【问题标题】:Programming recursive functions in alloy在合金中编程递归函数
【发布时间】:2013-09-26 02:45:48
【问题描述】:

我正在尝试在 Alloy 中构造一个递归函数。根据丹尼尔杰克逊书中显示的语法,这是可能的。我的功能是:

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]
        }       
    }
}

但求解器声称调用 auxiliaryToAvoidCyclicRecursion[idTarget, mRet] 时说:

"This must be a formula expression.
Instead, it has the following possible type(s):
{this/Method}"

【问题讨论】:

  • 您应该发布模型的其余部分,以便我们运行它。

标签: recursion alloy


【解决方案1】:

问题正是错误消息所说的: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 被建模为关系的同一个列表(即Node 中的字段)

sig Node {
  next: lone Node,
  len: one Int
} {
  this !in this.^@next
  (no this.@next) => this.@len = 1 else this.@len = plus[next.@len, 1]
}

// instance found
run { some n: Node | n.len > 4 } for 5 but 4 Int

请注意,后一种方法不使用递归(因此不依赖于“递归深度”配置选项的值),可能(并且通常是)明显慢于前者。

【讨论】:

  • 这么长又透彻的回答,可惜没有更多的点赞
猜你喜欢
  • 2019-05-17
  • 1970-01-01
  • 2015-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 1970-01-01
相关资源
最近更新 更多