TLA+ 《Specifying Systems》翻译初稿——Section 4.2 Instantiation Examined(审视实例化)

本节详细说明了模块实例化的几个方面:

  • 实例化本质上是一种代换,通过代换待实例化模块中的符号,最终得到的表达式只包含 T L A + TLA^+ 的内建运算符和当前模块定义的常量和参数;
  • 也可以将实例作为入参,这样只需要一条实例化定义语句即可;
  • 一条 INSTANCE \text{INSTANCE} 语句必须对待实例化模块的每个参数都有代换。如果有些参数 p p 没有显式的代换,那么必然有一个隐式的代换 p p p \leftarrow p
  • 只需要模块的一个实例时,可以不对实例重命名,如果有代换,则必须在参数的声明或定义的范围内定义 INSTANCE \text{INSTANCE} 语句;

在实际中除了用于隐藏变量这种习惯用法外,其实很少用到 INSTANCE \text{INSTANCE} 语句。所以,大多数读者可以跳过这一部分,直接翻到第4.3节。

4.2.1 实例化是一种代换(Instantiation Is Substitution)

考虑第30页 C h a n n e l Channel 模块中的 N e x t Next 的定义,我们可以将定义中的符号用该符号的定义来代替。例如,我们可以通过展开 S e n d Send 的定义来消除表达式 S e n d ( d ) Send(d) ,这个过程可以不断重复。表达式 1 @ 1-@ 中出现的“ - ”(通过展开 S e n d Send 的定义获得)可以通过使用 N a t u r a l s Naturals 模块中的“ - ”定义来消除,重复这种方式,我们最终获得 N e x t Next 的定义,它只包含 T L A + TLA^+ 的内建运算符和 C h a n n e l Channel 模块的参数 D a t a Data c h a n chan 。我们认为这是 C h a n n e l Channel 模块 N e x t Next 的“真正”定义。
在这里插入图片描述

I n C h a n INSTANCE  C h a n n e l  WITH  D a t a M e s s a g e , c h a n i n InChan \triangleq \text{INSTANCE }Channel \text{ WITH } Data \leftarrow Message,chan \leftarrow in

上述 I n n e r F I F O InnerFIFO 模块中定义的 I n C h a n ! N e x t InChan!Next 是在 N e x t Next 的“真正”定义中用 M e s s a g e Message 代换 D a t a Data i n in 代换 c h a n chan 之后得到的公式。这样定义的 I n C h a n ! N e x t InChan!Next 只有 T L A + TLA^+ 的内置运算符和模块 I n n e r F I F O InnerFIFO 的参数 M e s s a g e Message i n in

让我们考虑一条任意的 INSTANCE \text{INSTANCE} 语句:
I M INSTANCE  M  WITH  p 1 e 1 , , p n e n IM \triangleq \text{INSTANCE } M \text{ WITH }p_{1} \leftarrow e_{1},\cdots,p_{n} \leftarrow e_{n}

Σ \Sigma 为模块 M M 中定义的符号,设 d d 为其“真实”定义。 INSTANCE \text{INSTANCE} 语句定义 I M ! Σ IM!\Sigma 是通过对任一 i i ,将 d d 中的 p i p_{i} e i e_{i} 替换得到表达式。 I M ! Σ IM!\Sigma 的定义必须只包含当前模块的参数(已声明的常量和变量),而不包含模块 M M 的参数。因此, p i p_{i} 必须包含模块 M M 的所有参数, e i e_{i} 必须是在当前模块中有意义的表达式。

4.2.2 参数化实例化(Parametrized Instantiation)

FIFO规约使用了 C h a n n e l Channel 模块的两个实例,一个用 i n in 代换 c h a n chan ,另一个用 o u t out 代换 c h a n chan 。我们也可以使用一个单一的参数化实例,如:
C h a n ( c h ) INSTANCE  C h a n n e l  WITH  D a t a M e s s a g e , c h a n c h Chan(ch) \triangleq \text{INSTANCE }Channel \text{ WITH } Data \leftarrow Message,chan \leftarrow ch

对于定义在 C h a n n e l Channel 模块中的任意符号 Σ \Sigma 和任意表达式 e x p exp C h a n ( e x p ) ! Σ Chan(exp)!\Sigma 等价于在公式 Σ \Sigma 中用 M e s s a g e Message 代换 D a t a Data ,用 e x p exp 代换 c h a n chan 。在通道 i n in 上的动作可以被记作 C h a n ( i n ) ! R c v Chan(in)!Rcv S e n d ( m s g ) Send(msg) o u t out 通道上也可以记作 C h a n ( o u t ) ! S e n d ( m s g ) Chan(out)!Send(msg)

上述实例化定义了 C h a n ! S e n d Chan!Send 为有两个入参的运算符。用 C h a n ( o u t ) ! S e n d ( m s g ) Chan(out)!Send(msg) 取代 C h a n ! S e n d ( o u t , m s g ) Chan!Send(out,msg) 只是语法的一种特性,它看起来和中缀运算符的语法一样奇怪。(中缀运算符要求我们写 a + b a + b 而不是 + ( a , b ) +(a,b) 。)

参数化实例化仅在 T L A + TLA^+ 语言中用于变量隐藏,在后面的第4.3节中有描述。你可以在不了解它的情况下使用它,不了解任何有关参数化实例化的知识也没关系。

扫描二维码关注公众号,回复: 8907265 查看本文章

4.2.3 隐式代换(Implicit Subsititutions)

因为我们之前在异步 C h a n n e l Channel 规约中的使用了命名 D a t a Data ,在FIFO规约中使用 M e s s a g e Message 作为传输数值集合的名称就有点奇怪了,假设我们使用 D a t a Data 代代替 M e s s a g e Message 作为 I n n e r F I F O InnerFIFO 模块的常量参数,第一条实例化语句应该是:
I n C h a n INSTANCE  C h a n n e l  WITH  D a t a D a t a , c h a n i n InChan \triangleq \text{INSTANCE }Channel \text{ WITH } Data \leftarrow Data,chan \leftarrow in

D a t a D a t a Data \leftarrow Data 代换表示用当前模块的表达式 D a t a Data 代换实例化 C h a n n e l Channel 模块的常量参数 D a t a Data T L A + TLA^+ 允许我们删除任何形式的代换 Σ Σ \Sigma \leftarrow \Sigma 。因此,上面的表述可以写成
I n C h a n INSTANCE  C h a n n e l  WITH  c h a n i n InChan \triangleq \text{INSTANCE }Channel \text{ WITH } chan \leftarrow in

我们知道存在一个隐含的 D a t a D a t a Data \leftarrow Data 代换是因为一条 INSTANCE \text{INSTANCE} 语句必须对实例化模块的每个参数都有代换。如果有些参数 p p 没有显式的代换,那么必然有一个隐式的代换 p p p \leftarrow p 。这意味着 INSTANCE \text{INSTANCE} 声明必须在符号 p p 的声明或者定义的范围内。

用隐式代换进行实例化操作是比较常见的。通常,每个参数都有一个隐式代换,在这种情况下,显式代换列表是空的, WITH \text{WITH} 语句可以被省略。

4.2.4 无重命名的实例化(Instantiation Without Renaming)

到目前为止,我们使用的所有实例化都与重命名有关。例如, C h a n n e l Channel 模块的第一条实例化语句将定义的符号 S e n d Send 重命名为 I n C h a n ! S e n d InChan!Send 。如果要使用模块的多个实例或单个参数化实例,则需要使用这种重命名。模块 I n n e r F I F O InnerFIFO 中的 I n C h a n ! I n i t InChan!Init O u t C h a n ! I n i t OutChan!Init 是不同的公式,它们需要不同的命名。

有时我们只需要模块的一个实例。例如,假设我们要定义的系统只有一个异步通道,则我们只需要一个 C h a n n e l Channel 实例,因此不必重命名。在这种情况下,我们可以这样写:
INSTANCE  C h a n n e l  WITH  D a t a D , c h a n x \text{INSTANCE }Channel \text{ WITH }Data \leftarrow D,chan \leftarrow x

上述 C h a n n e l Channel 的实例化语句没用重命名,但是使用了代换,它将 R c v Rcv 定义为 C h a n n e l Channel 模块中的同名公式,只是其中用 D D 代换了 D a t a Data ,用 c h a n chan 代换了 x x 。在使用表达式代换实例化模块的参数之前必须先定义它,所以这个 INSTANCE \text{INSTANCE} 语句必须在 D D x x 的定义或声明的范围之内。

发布了4 篇原创文章 · 获赞 1 · 访问量 5750

猜你喜欢

转载自blog.csdn.net/robinhzp/article/details/104091930