添加到@Hovercouch 的答案:与编程语言不同,“删除”不符合 TLA+ 规范的含义。
声明dictionary
为 aVARIABLE
表示它是不带参数( nullarydictionary
)的运算符的标识符,并且可以根据行为(“随着时间”)更改值。它没有说别的。
查看步骤(行为中的一对连续状态),dictionary
(在第一个状态中)的值和dictionary'
(dictionary
在第二个状态中的)的值是不相关的 [1, p.313]。只有通过规范中表达的约束,我们才能限制它们的值。
如果处于 state dictionary = [x \in {"foo", "bar"} |-> x]
,则dictionary'
可以是任何东西(ZF中的任何值,即任何集合)。见[1,秒。第 72 页,第 6.5 节。“不要……”在第 80 页,第 139--140 页]。
状态谓词的值
dictionary["foo"] = "foo"
在这种状态下TRUE
,因为确实dictionary
将值映射"foo"
到值"foo"
。相反,状态谓词:
dictionary["foo"] = "bar"
是FALSE
,因为"foo" # "bar"
。如果在以该状态为第一个状态的步骤中,我们编写(另见 [1, p.82]):
(dictionary["foo"] = "foo")'
我们只是说表达式在下一个状态中dictionary["foo"]
等于。我们没有说那是那个状态下的函数——只是说它是一个恰好等于 equal的值。也许那里没有功能。"foo"
dictionary
dictionary["foo"]
"foo"
dictionary
什么是函数?
我们什么时候将给定的值f
称为“函数”?答案是f
恰好满足公式IsAFunction(f)
,其中运算符IsAFunction
定义为 [1, p.303]:
IsAFunction(g) == g = [x \in DOMAIN g |-> g[x]]
元组(“数组”)是1..n
一些具有域的函数n \in Nat
。在 TLA+ 中,函数只是具有上述属性的值。由于 ZF 中的任何值都是一个集合,因此函数也是集合,因为我们仍然可以写y \in f
when f
is a function [1, above Sec. 第 43 页的第 4.5 节和第 30 页的第 3.3 节]。
例如,使用定理证明器TLAPS,我们可以证明以下定理并使用Isabelle通过运行来检查证明tlapm -v -C test.tla
:
---- MODULE test ----
EXTENDS TLAPS
f == [x \in {} |-> x]
g == [x \in {1, 2} |-> 3]
THEOREM
LET
S == f \cup {g}
IN
(1 \in f) => (1 \in S)
PROOF BY Zenon
(* you can replace this with OBVIOUS *)
=====================
(模型检查器TLC枚举状态,并且由于我们不知道恰好是函数的集合中包含哪些元素,因此 TLC 无法评估表达式y \in f
,从而引发Error: Attempted to check if the value: ... is an element of the function ...
. 句法分析器SANY确认上述模块很好-形成。)
我们也可以写f[x]
when f
is not a function 或 when x \notin DOMAIN f
。问题是在这些情况下,值f[x]
是未指定的,因此规范不应取决于这些值是什么。
对规范的评论
该表达式dictionary = []
不是 TLA+ 的一部分。要编写具有空域的函数(只有一个这样的函数,请参阅关于函数可扩展性的公理 [1, p.303]):
dictionary = [x \in {} |-> TRUE]
我将声明capacity
为 a CONSTANT
,因为它旨在对行为保持不变(当然,除非它发生变化)。此外,currentSize
规范并没有减少,但我认为这还没有被添加。
还值得注意的是,dictionary
将每个项目映射到一个唯一的值,而queue
最终可以包含同一项目的多个副本。不确定 OP 对这种情况有何打算。
EXTENDS Integers, Sequences
CONSTANT capacity
VARIABLES currentSize, queue, dictionary
Init == /\ (capacity = 3 ) /\ (currentSize = 0)
/\ (queue = <<>>) /\ (dictionary = [x \in {} |-> TRUE])
AddItem(Item, Value) ==
IF currentSize < capacity
(* Overwrite to what value the dictionary maps
the value. *)
THEN /\ currentSize' = currentSize + 1
/\ queue' = Append(queue, Item)
/\ dictionary' =
[x \in DOMAIN dictionary |->
IF x = Item
THEN Value
ELSE dictionary[x]]
(* Remove the leading item from the dictionary's domain,
then add the given item (perhaps the same), and
map it to the given value. *)
ELSE /\ queue' = Append(Tail(queue), Item)
/\ LET
(* It can happen that OldDom = NewDom. *)
OldDom == DOMAIN queue
first == queue[1]
TailDom == OldDom \ { first }
NewDom == TailDom \cup {Item}
IN
dictionary' =
[x \in NewDom |->
IF x = Item
THEN Value
ELSE dictionary[x]]
GetItem(Item) == dictionary[item]
Next == \/ AddItem
\/ GetItem
表达方式
dictionary' = [x \in DOMAIN dictionary |->
IF x = Item THEN Value ELSE dictionary[x]]
可以替换为 [1, p.49]
dictionary' = [dictionary EXCEPT ![Item] = Value]
表达方式
dictionary' = [x \in NewDom |->
IF x = Item THEN Value ELSE dictionary[x]]
不能替换为EXCEPT
。
参考
[1] Leslie Lamport,“指定系统”,Addison-Wesley,2002