我正在玩TLA+,并认为我会在PlusCal中编写以下明显错误的规范:
telephone
在将---- MODULE transfer ----
EXTENDS Naturals, TLC, Sequences
(* --algorithm transfer
\* Simple algorithm:
\* 1. Start with a shared-memory list with one element.
\* 2. A process adds arbitrary numbers of elements to the list.
\* 3. Another process removes arbitrary numbers of elements from the list,
\* but only if the list has more than one item in it. This check is
\* applied just before trying to removing an element.
\* Is it true that the list will always have a length of 1?
\* You would expect this to be false, since the adder process can add more elements
\* than the remover process can consume.
variables stack = <<0>>
process Adder = 0
begin
AddElement:
stack := Append(stack, Len(stack));
either goto AddElement
or skip
end either;
end process;
process Remover = 1
begin
RemoveElement:
\* Pop from the front of the stack
if Len(stack) > 1 then
stack := Tail(stack);
end if;
either goto RemoveElement
or skip
end either;
end process;
end algorithm *)
IsStackAlwaysUnitLength == Len(stack) = 1
====
作为要报告的时间属性之一后,我希望TLA +将此属性标记为失败。
但是,所有状态都通过了!为什么它不会失败?
在使用IsStackAlwaysUnitLength
语句进行调试时,我注意到以下奇怪行为:
print
在调试面板中显示产量
process Adder = 0
begin
AddElement:
print stack;
print "Adder applied!";
stack := Append(stack, Len(stack));
print stack;
print "Adder task complete!";
\* Force
either goto AddElement
or skip
end either;
end process;
process Remover = 1
begin
RemoveElement:
\* Pop from the front of the stack
print stack;
print "Remover applied!";
if Len(stack) > 1 then
stack := Tail(stack);
print stack;
print "Remover task complete!";
else
print "Remover task complete!";
end if;
either goto RemoveElement
or skip
end either;
end process;
我不确定为什么<<0>>
"Adder applied!"
<<0>>
"Adder task complete!"
<<0>>
<<0>>
"Remover applied!"
"Remover applied!"
"Remover task complete!"
"Remover task complete!"
<<0>>
"Adder applied!"
<<0>>
"Adder task complete!"
和stack := Append(stack, Len(stack));
没有更新全局stack := Tail(stack);
变量。
stack
答案 0 :(得分:2)
恭喜,您遇到了PlusCal错误!而且这不是一个漏洞,但仍然不直观。让我们从错误开始。
有时使用PlusCal时,我们希望多个进程共享标签。我们通过过程来实现。为了使其全部正常工作,PlusCal转换器添加了一个额外的簿记变量,称为stack
。 通常,如果用户定义的变量foo
与生成的变量foo
冲突,则转换会将其重命名为foo_
。在这种情况下,由于没有冲突,因此没有任何重命名。*错误在于,翻译人员感到困惑,并翻译了变量,好像被认为是簿记{{1} }。您可以看到它将附加变成
stack
什么时候应该出现
stack' = [stack EXCEPT ![0] = Append(stack, Len(stack))]
您可以通过将stack' = Append(stack, Len(stack))
重命名为stack
来解决此问题。这样可以正确显示规范。但是它仍然会通过:那是因为您将mystack
当作属性而不是不变。作为时间属性,IsStackAlwaysUnitLength
如果在初始状态下为true,则为true。作为不变式,IsStackAlwaysUnitLength
在 all 状态下都是正确的。**通过将IsStackAlwaysUnitLength
从时态属性更改为IsStackAlwaysUnitLength
,可以使规范正确失效。 “什么是模型”页面中的。
*实际上,在这种情况下,如果添加过程,翻译器将不会重命名stack
,而只会引发错误。但这仍然是安全的。
**这是因为TLC(模型检查器)将不变的P
视为时间属性[]P
。基本上是语法糖。