所以我有这个mwe:
abstract sig S { r: set S }
one sig A, B extends S {}
one sig C { }
run { r = A->B and A->A + B->B + A->B = *r }
我期望反身传递闭包为A->A + B->B + A->B
,这是最小的传递和反身的封闭关系,包含为其定义的域中的所有元素(S = A+B
) 。但事实并非如此。
在语言参考中它说
关系的反身 - 传递闭包是传递和反身的最小封闭关系(即包括身份关系)。
然而,括号中的加法似乎是字面上的意思,意味着C->C
处于为S->S
定义的关系的反身 - 传递闭包中。我想知道为什么会这样......因为它在技术上不在数学中定义的“真正的”反射 - 传递闭包中。
*r = ^r + iden & S->S
会不会更好?特别是,因为C->C in *r
会发出警告。我认为这表明*r
确实意味着仅限于S->S
,但实际仅限于S->S
。
答案 0 :(得分:3)
是的,这是关于Alloy' *运算符的一件事,偶尔会令人惊讶。杰克逊在软件抽象的第3.4.3.5节(修订版中的第65-66页)之后的问题中对此进行了讨论。提供的解释是:
虽然这看起来很奇怪,但它自然地来自于反身 - 传递闭包的定义和身份关系。另一种方法是让每个关系隐含地与表示其域和范围的可能成员相关联,这会使逻辑复杂化。
他接着指出,这在实践中很少成为问题,因为当在导航表达式中使用传递闭包时,不相关的元组将在连接中消失,而如果不是,写入S <: *r
也将过滤超出非S元组。我的经历证实了杰克逊的说法:我记得这一点,因为我非常惊讶,有一次我在实践中遇到了这个问题。八年一次(诚然,我不会花费我所有的时间来写合金模型)似乎是一个相当温和的发生率。 (翻译:是的,它很令人惊讶。但你可以学会忍受它。我保证。)
我推断C->C in *r
上的警告并不表示*
旨在排除不相关的三元组;它可能是一个确认(如3.4.3.5中的讨论),许多用户在关系的传递闭包中发现意外配对时有点吃惊。
我希望这会有所帮助。
答案 1 :(得分:0)
向CMS提出一个好的答案......
你问
不会* r = ^ r + iden&amp; S-> S更好吗?
但这不是一种选择 - 至少不是很明显。原因是我们不知道S是什么,所以它需要被推断(这可能会产生一些奇怪的情况),或者需要明确给出。