在my last Stack Overflow post中,我问如何创建一个Alloy模型,该模型限制每个反斜杠被另一个反斜杠转义,前提是反斜杠不会转义为逗号。 Daniel Jackson回复了我的帖子,建议我的模型应该更抽象。事实上,我已经创建了一个更抽象的模型。但我觉得它过于抽象,它避免了正确约束反斜杠的问题(见this post)。
我很困惑,什么时候合金模型太抽象了,什么时候不够抽象?
答案 0 :(得分:0)
首先,我认为你的模型对底层世界模型的表达过于复杂。我认识到你正在努力解决的问题,逃避。这肯定是一个令人讨厌的领域。
对我而言,关键是让模型使用seq
,因为它是一系列Char。
abstract sig Char {}
abstract sig EscapedCharacter extends Char {}
one sig A,B,C extends Char {}
one sig Backslash, Comma extends EscapedCharacter {}
pred valid[ string : seq Char ] {
string.isEmpty
or
string[0] = Backslash
implies {
# string > 1
and string[1] in EscapedCharacter
and valid[ string.subseq[2,#string]]
}
else string[0] != Comma and valid[ string.rest ]
}
run valid for 4
不幸的是,这使用了递归。我实际上失败了如何在没有递归的情况下指定它,但我试图找出答案。不幸的是,因为你需要在菜单中启用递归,这仅限于3个级别,即使很小的问题也是如此。这种限制的原因是递归需要展开,这会爆炸状态空间。 但是,我希望我们能找到一种让递归更像是一等公民的方法,因为大多数开发人员的可读性都很高。
无论如何,当我们断言一些例子时它看起来很有用:
assert InvalidExample {
not valid[ 0->Backslash ]
}
check InvalidExample for 4
assert InvalidExample2 {
not valid[ (0->A) + (1->Backslash) + (2->Backslash)+ (3->Comma) ]
}
check InvalidExample2 for 4
assert ValidExample {
valid[ (0->Backslash) + (1->Comma) ]
}
check ValidExample for 4
已更新错过原始要求逗号必须始终前面加一个反斜杠(我应用了我的常识,而不是按字面意思读取。)