从前面的例子中已经可以看到,QCP的断言语言中可以使用逻辑连接词&&与*,前者表示通常意义上的“且”,而后者是分离合取,具体而言,“P * Q”表示当前内存可以分为互不相交的两部分,其中一部分满足P另一部分满足Q。我们可以用这些逻辑连接词将多个子句连接起来,从而表述一些复杂的概念。
假如p是一个逻辑变量,它的值是一个内存地址,那么
exists v, v >= 0 && store_int(p, v)
就表示地址p上存储了一个非负数。
假如p与q都是逻辑变量,它们的值都是内存地址,那么
exists v, store_int(p, v) * store_int(q, v)
就表示p与q是不同的地址,但是两个地址上存储了一个相同的数。
当然,我们也可以写出更复杂一些的断言:
exists v, store_int(p, v) * store_int(q, v)
这就表示就表示p与q是不同的地址,但是两个地址上存储了一个相同的非负数。
前面已经介绍,分离合取(“*”)具有交换律与结合律,换言之
P * Q <----> Q * P
P * (Q * R) <----> (P * Q) * R
它还有以下两条重要性质:
-
&&与*的结合律:如果P是一个与内存无关的命题(如大小比较v >= 0等),那么(P && Q) * R <----> P && (Q ** R)。这个等价式的左边说的是内存空间可以分为两部分,其中之一满足P && Q而另一个满足R。由于P是一个与内存无关的命题,因此这也就相当于说P成立,并且内存可以分为两部分,分别满足Q与R,这也就是等价式右边所描述的性质。 由于此性质的原因,当&&连接的P是与内存无关的式子时,P && Q * R这样的式子可以不加括号说明&&与*之间的结合顺序。 -
exists与*的结合律:(exists x, P(x)) * Q <----> exists x, (P(x) * Q)。由于此性质的原因,我们总是可以把分离合取子句中的exists提到最外侧。