TLA+ 《Specifying Systems》翻译初稿——Section 6.3 Recursion Revisited (递归回顾)

本节要点:

  • TLA+中, f [ x S ] e f[x \in S] \triangleq e
    (6.3) f CHOOSE  f : f = [ x S e ] f \triangleq \text{CHOOSE } f:f=[x\in S \mapsto e] 的缩写形式;
  • TLA+允许我们写“笨定义”,例如,我们可以写
    (6.4) c i r c [ n N a t ] CHOOSE  y : y c i r c [ n ] circ[n\in Nat]\triangleq \text{CHOOSE }y:y\neq circ[n] ,不过在TLA+中,函数 c i r c circ 的值不确定;
  • TLA+不允许相互循环定义。不过,我们可以按TLA+允许的方式这样定义函数 f f g g : 先定义一个函数 m r mr 使得 m r [ n ] mr[n] 是一个record,它的 f f g g 域分别为 f [ n ] f[n] g [ n ] g[n]
    m r [ n S ] [ f IF     n = 0    THEN     17     ELSE     m r [ n 1 ] . f m r [ n ] . g , g IF     n = 0    THEN     42     ELSE     m r [ n 1 ] . f + m r [ n 1 ] . g ] \\mr[n \in S]\triangleq \\ \quad [f \mapsto \text{IF } \;n=0 \; \text{THEN }\; 17\; \text{ ELSE }\; mr[n-1].f*mr[n].g, \\ \quad g \mapsto \text{IF } \;n=0 \; \text{THEN }\; 42\; \text{ ELSE }\; mr[n-1].f+mr[n-1].g ]
    之后我们可以根据 m r mr f f g g 定义为: f [ n N a t ] m r [ n ] . f g [ n N a t ] m r [ n ] . g f[n \in Nat] \triangleq mr[n].f \\g[n \in Nat] \triangleq mr[n].g 这个小技巧可以将任何相互循环函数定义转换为 定义一个独立的record-valued 循环定义函数,这个函数的域即为想要相互循环定义的函数。

-第5.5章有引入递归函数定义。我们现在看一下这些定义的数学含义。数学家们将阶乘函数定义如下: f a c t [ n ] = IF  n = 0  THEN  1  ELSE  n f a c t [ n 1 ] , f o r    a l l    n N a t fact[n]=\text{IF } n=0\text{ THEN } 1\text{ ELSE } n * fact[n-1], for \;all \;n \in Nat 上述通常被认为是唯一定义了 N a t Nat 域上的函数 f a c t fact ,换句话说, f a c t fact 是唯一满足
(6.1) f a c t [ n ] = IF  n = 0  THEN  1  ELSE  n f a c t [ n 1 ] fact[n]=\text{IF } n=0\text{ THEN } 1\text{ ELSE } n * fact[n-1] 公式的值。

5.1节P47-48页引入的 CHOOSE \text{CHOOSE} 操作符, 让我们可以用 CHOOSE  x : p \text{CHOOSE } x:p 表达 “选个x满足属性p”的需求。因此我们定义 f a c t fact 如下:
(6.2) f a c t CHOOSE  f a c t : f a c t = [ n N a t IF  n = 0  THEN  1  ELSE  n f a c t [ n 1 ] fact \triangleq \text{CHOOSE } fact: \\ \qquad \qquad \qquad fact=[n \in Nat \mapsto \text{IF } n=0\text{ THEN } 1\text{ ELSE } n * fact[n-1]
(因为符号 f a c t fact \triangleq 右侧引入之前尚未在表达式中有定义,我们只能在 CHOOSE \text{CHOOSE} 表达式中将它用做绑定标识符)。TLA+的定义 f a c t [ n N a t ] IF  n = 0  THEN  1  ELSE  n f a c t [ n 1 ] fact[n \in Nat] \triangleq \text{IF } n=0\text{ THEN } 1\text{ ELSE } n * fact[n-1] 只是(6.2)的缩写形式。再推广一下, f [ x S ] e f[x \in S] \triangleq e
(6.3) f CHOOSE  f : f = [ x S e ] f \triangleq \text{CHOOSE } f:f=[x\in S \mapsto e] 的缩写形式。

TLA+允许我们写“笨定义”,例如,我们可以写
(6.4) c i r c [ n N a t ] CHOOSE  y : y c i r c [ n ] circ[n\in Nat]\triangleq \text{CHOOSE }y:y\neq circ[n] ,意思是 对任意自然数 n n , 定义一个函数 c i r c circ ,使得 c i r c [ n ] c i r c [ n ] circ[n] \neq circ[n] 。 很显然没有这样的函数,所以 c i r c circ 不可能定义出来。在一个递归函数定义中不是很有必要再定义一个函数。如果没有函数 f f 等于 [ x S e ] [x \in S \mapsto e] , 则(6.3) 定义 f f 为一个不确定的值,这样,(6.4)也将 c i r c circ 定义为一个未知数。

虽然TLA+允许递归函数定义具有明显的循环性,但它不允许循环定义(在循环定义中,两个或多个函数是相互定义的)。数学家们偶尔会写这样的循环定义。例如,他们会这样定义自然数域上的函数 f f g g
f [ n ] = i f    n = 0    t h e n    17    e l s e    f [ n 1 ] g [ n ] , g [ n ] = i f    n = 0    t h e n    42    e l s e    f [ n 1 ] g [ n 1 ] f[n]=if \;n=0 \; then\; 17\; else \; f[n-1]*g[n], \\ g[n] = if \;n=0 \; then\; 42\; else \; f[n-1]*g[n-1]
TLA+不允许相互循环定义。不过,我们可以按TLA+允许的方式这样定义函数 f f g g :先定义一个函数 m r mr 使得 m r [ n ] mr[n] 是一个record,它的 f f g g 域分别为 f [ n ] f[n] g [ n ] g[n]
m r [ n S ] [ f IF     n = 0    THEN     17     ELSE     m r [ n 1 ] . f m r [ n ] . g , g IF     n = 0    THEN     42     ELSE     m r [ n 1 ] . f + m r [ n 1 ] . g ] \\mr[n \in S]\triangleq \\ \quad [f \mapsto \text{IF } \;n=0 \; \text{THEN }\; 17\; \text{ ELSE }\; mr[n-1].f*mr[n].g, \\ \quad g \mapsto \text{IF } \;n=0 \; \text{THEN }\; 42\; \text{ ELSE }\; mr[n-1].f+mr[n-1].g ]
之后我们可以根据 m r mr f f g g 定义为: f [ n N a t ] m r [ n ] . f g [ n N a t ] m r [ n ] . g f[n \in Nat] \triangleq mr[n].f \\g[n \in Nat] \triangleq mr[n].g
这个小技巧可以将任何相互循环函数定义转换为 定义一个独立的record-valued 循环定义函数,这个函数的域即为想要相互循环定义的函数。

如果我们想推导出由 f [ x S ] e f[x\in S] \triangleq e 定义的函数 f f ,我们需要证明存在一个 f f 等于 [ x S e ] [x \in S \mapsto e]
如果 f f 没有出现在 e e 中, f f 的存在性是很明显的。如果它出现了,那么这就是一个递归定义,然后就需要得到证明。不过本书中我们不讨论如何证明它。直观上,你必须检查一下,就像在阶乘函数的情况下,这个定义唯一地确定了 S S 中每一个 x x 对应的 f [ x ] f[x] 的值。

递归是一种常见的编程技术,因为程序必须使用少量简单基本的操作来计算数值。它在数学定义中不常用,在数学定义中我们不必担心如何计算数值,因为可以使用强大的工具如逻辑运算符和集合论来计算。例如,在5.4节中定义了操作符Head、Tail和o,但没有使用递归(尽管计算机科学家通常使用递归的方式来定义它们)。尽管如此,使用递归函数定义还是可以最好地归纳定义某些东西。

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

猜你喜欢

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