这个 sig 如何添加到 Alloy 中的关系中?
how is this sig being added to a relation in Alloy?
我正在 Alloy 中建模一个 Google 类文档内联评论系统。具体来说,我正在对用户可以执行的 UI 交互进行建模。用英语表示的约束是:
- 用户可以有任意数量的评论
- 用户可以同时撰写任意数量的评论
- 评论可以是撰写或编辑,不能同时是
- (最终)用户可以一次展开一条评论来查看它——否则文本会被 运行 处理。
到目前为止,我只模拟了添加新评论——或者我认为如此!当我 运行 下面的模型时,我希望看到 Alloy 找不到任何反例,但它找到了一个评论在 composed
和 composing
关系中的一次。
我认为 Alloy 在这种情况下的运作方式可能与我的心智模型不符。我看不出如何将评论添加到此处的 composed
关系:我认为 init
会将所有草稿设置为在那里具有空关系,并且 Traces
中的操作会阻止将评论添加到 composed
。但!我显然错了,因为 Alloy 找到了一个 composed
非空的例子。有谁知道这里到底发生了什么?
module inlineComments
open util/ordering [Time] as TimeOrdering
sig Time {}
sig Draft {
composing: set Comment -> Time,
composed: set Comment -> Time,
-- expanded: lone Comment -> Time,
}
sig Comment {}
-- What can we do with these?
pred newComment (t, t': Time, c: Comment, d: Draft) {
-- comment is not already known to us
c not in d.composing.t
c not in d.composed.t
-- start composing the comment
d.composing.t' = d.composing.t + c
}
pred init (t: Time) {
all d: Draft, c: Comment | c not in d.composing.t
all d: Draft, c: Comment | c not in d.composed.t
}
fact Traces {
init[TimeOrdering/first]
all t: Time - TimeOrdering/last |
let t' = TimeOrdering/next[t] |
some d: Draft, c: Comment |
newComment [t, t', c, d]
}
-- Is the world how we expect it to be?
assert validState {
-- comments cannot be composing and composed at the same time
all t: Time, d: Draft | d.composing.t & d.composed.t = none
}
check validState for 3 but 1 Draft
这就是所谓的 "frame problem":您已经指定可以将新评论放入 composing
,但并不是说什么都不会发生!您必须明确表示系统可能更改的唯一方法是 via newComment
。这是您可以做到的一种方法:
fact Traces {
init[TimeOrdering/first]
all t: Time - TimeOrdering/last |
let t' = TimeOrdering/next[t] |
some d: Draft, c: Comment {
newComment [t, t', c, d]
d.composed.t = d.composed.t' -- d.composed doesn't change
}
}
请注意,这仅适用于您已明确将范围限定为最多 1 个草稿。如果您使用两个草稿进行测试,您还必须证明 none 个草稿以任何方式发生了变化。如果总是只有一个草案,您可以写 one sig Draft
来强制执行。
我正在 Alloy 中建模一个 Google 类文档内联评论系统。具体来说,我正在对用户可以执行的 UI 交互进行建模。用英语表示的约束是:
- 用户可以有任意数量的评论
- 用户可以同时撰写任意数量的评论
- 评论可以是撰写或编辑,不能同时是
- (最终)用户可以一次展开一条评论来查看它——否则文本会被 运行 处理。
到目前为止,我只模拟了添加新评论——或者我认为如此!当我 运行 下面的模型时,我希望看到 Alloy 找不到任何反例,但它找到了一个评论在 composed
和 composing
关系中的一次。
我认为 Alloy 在这种情况下的运作方式可能与我的心智模型不符。我看不出如何将评论添加到此处的 composed
关系:我认为 init
会将所有草稿设置为在那里具有空关系,并且 Traces
中的操作会阻止将评论添加到 composed
。但!我显然错了,因为 Alloy 找到了一个 composed
非空的例子。有谁知道这里到底发生了什么?
module inlineComments
open util/ordering [Time] as TimeOrdering
sig Time {}
sig Draft {
composing: set Comment -> Time,
composed: set Comment -> Time,
-- expanded: lone Comment -> Time,
}
sig Comment {}
-- What can we do with these?
pred newComment (t, t': Time, c: Comment, d: Draft) {
-- comment is not already known to us
c not in d.composing.t
c not in d.composed.t
-- start composing the comment
d.composing.t' = d.composing.t + c
}
pred init (t: Time) {
all d: Draft, c: Comment | c not in d.composing.t
all d: Draft, c: Comment | c not in d.composed.t
}
fact Traces {
init[TimeOrdering/first]
all t: Time - TimeOrdering/last |
let t' = TimeOrdering/next[t] |
some d: Draft, c: Comment |
newComment [t, t', c, d]
}
-- Is the world how we expect it to be?
assert validState {
-- comments cannot be composing and composed at the same time
all t: Time, d: Draft | d.composing.t & d.composed.t = none
}
check validState for 3 but 1 Draft
这就是所谓的 "frame problem":您已经指定可以将新评论放入 composing
,但并不是说什么都不会发生!您必须明确表示系统可能更改的唯一方法是 via newComment
。这是您可以做到的一种方法:
fact Traces {
init[TimeOrdering/first]
all t: Time - TimeOrdering/last |
let t' = TimeOrdering/next[t] |
some d: Draft, c: Comment {
newComment [t, t', c, d]
d.composed.t = d.composed.t' -- d.composed doesn't change
}
}
请注意,这仅适用于您已明确将范围限定为最多 1 个草稿。如果您使用两个草稿进行测试,您还必须证明 none 个草稿以任何方式发生了变化。如果总是只有一个草案,您可以写 one sig Draft
来强制执行。