编程的实践理论 第三章 函数理论

第三章 函数理论

如果我们解释规则的使用,我们总是允许发明新的语法。新的语法的
一个好的来源是名称(标识符),通过公理给出了规则是如何使用的。
通常,当我们介绍名称和公理时,我们要它们实现当前的目的。读者
被假定理解它们的作用域,就是它们的应用范围,在它的范围外不使用。
尽管名称和公理是形式化的(在我们的形式化中的表达式),到现在
为止,我们已经用自然语言非形式化地介绍了它们。但是非形式化地
介绍名称和公理的作用域并不总是很清楚的。在这一章中,我们使用
了一个形式化的记号,来介绍本地化的名称和公理。

一个变量是一个名称,它的引用是为了替换它的值。例如定律 x*1=x
使用了变量x来告诉我们任何一个数乘以1等于同一个数。一个常量也是
一个名称,它的值不能被替换。例如,我们引入了一个名称pi,公理是
3.14<pi<3.15,但是我们不是说每个数都在3.14和3.15之间。相似的是,
我们引入了i 和公理 i*i=-1 并且,我们没有想要替换i。

函数的记号是引入了局部变量结合上局部的公理的形式化的方式,它说明
什么样的表达式能被用来替换变量。


3.0  函数

让v是一个名字,让D是一个项的束,让b是任意的表达式。那么,
<v:D→b>                    "在D中把v映射成b","在D中,本地的
v映射成b"  是变量v的函数在域D中,有函数体b.   包含关系
v:D 是一个本地的公理,带着函数体b. 方括号<> 显示出了
变量和公理的作用域。例如,
<n:nat → n+1> 是在自然数中,加一的自增函数。这有它的图
            0
0  →     1
1 →      2
2 →      3
3 →      4
.           .
.           .
.           .

如果 f是一个函数,那么,
口f                “f的域”
是它的域 ,域的公理是
口<v:D→b> = D
我们说D是函数<v:D→b>的域,也是变量v的域。一个函数的范围
包括在函数体中的变量的域中,通过替换每个元素,得到元素的范围。
我们的增量函数的范围是 nat+1。

一个函数引入了一个变量,或者说是一个参数。变量的目的是为了帮助
表达从域的元素到范围的元素的映射。只要名称是新的,没有已经被
用于其它目的,名称的选择是无关紧要的。重命名的公理说如果v和w
都是名称,并且它们都没有出现在域Dk ,并且w没有出现在b中,那么,

<v:D→b> = <w:D→(在b中所有的v替换成w)>
这种替换必须是每一处出现v的地方都替换成w。

如果f是一个函数 并且x是它的域中的一个元素,那么
fx       "函数f 参数是x"
对应的是范围的元素。这是函数应用,x是形式参数。当然了,
括号能用在任何表达式的周围,所以我们可以写成f(x)。如果函数
或者是参数不是简单的,我们将不得不把它用括号括起来。当没有
混淆的危险时,我们可以写fx,而不用写空格,但是当我们写多个字符
的名称时,我们必须在函数和它的参数之间加上空格。作为一个应用
的例子, 如果 suc=<n:nat→n+1> ,那么
suc 3 = <n:nat→n+1> 3 = 3+1 =4

这里有应用的公理。如果元素x在域D内,那么,
<v:D→b> x = (在b中所有的v替换成w)

操作符与函数是相似的,正如我们把操作符-
应用于x,就得到了-x。我们应用了函数f到形式
参数x上,得到了fx。

超过一个变量的函数是一个函数,它的函数体
是一个函数。这里有两个例子。

max = <x:xrat→<y:xrat→if x≥y then x else y fi>>
min = <x:xrat→<y:xrat→if x≤y then x else y fi>>

如果我们应用max到一个形式参数,我们得到了一个函数,
还带有一个变量。

max 3 =<y:xrat→if 3≥y then 3 else y fi>
当我再应用一个参数时,得到了一个结果值。
max 3 5 = 5

一个预测语句是一个函数,它的函数体是一个二进制的表达式。
两个例子是
even  = <i:int→i/2:int>
odd   = <i:int→¬i/2:int>

一个关系是一个函数,它的函数体是一个预测语句。
这是一个例子:
divides = <n:nat+1→<i:int→i/n:int>>
divides 2 = even
divides 2 3 = ⊥

在函数中一个更常见的操作是选择性的并。如果 f 和 g
是函数,那么 f|g  "f或者g" "f和g的选择性并"
是一个函数,如果把参数应用于f的域,它的行为f,否则
像g. 公理是
口(f|g)= 口f,口g
(f|g) x = if x:口f then fx else gx fi

证明的所有的规则应用于函数的函数体,附加的本地公理是
新的变量是域的元素。

    3.0.0  缩写的函数的标记

部分为了便利,部分为了传统,我们允许在函数的记号上有
一些改变。第一个改变是对变量的引入的分组。例如,
<x,y:xrat→if x≥y then x else y fi>    
是之前看到的最大值函数的一个缩写。

如果有额外的解释,我们可能忽略一个函数的域。例如,
自增函数可能写成<n→n+1>。这是在一个上下文中,能
理解到它的域是nat时的简写。

当函数体没有使用变量时,我们可以忽略到变量。
在这个方面,我们也能忽略掉方括号。例如 当我们
写着<n:2→3>,这里的n是没有用上的,于是可以缩写为,
2→3是一个函数,它把2映射成3.

一些人倾向于用任何的表达式来作为一个有变量的函数。
例如 他们可能写x+3,并且说它是x的一个函数。他们
忽略了形式变量,和域的引入,这是非形式化的提供内容。
这是缩写的问题。一个问题是可能有变量没有出现在表达式中。
例如,<x:int→<y:int→ x+3>> 它有两个变量,与下面的缩写
表达的内容是一样的。
<x:int→ x+3>
另一个问题是,没有精确地引入变量的作用域。还有
我们也不知道变量引入的顺序,所以我们无法把这个缩写
的函数应用于形式参数。我们认为缩写太过了,我们
将不使用它。我们仅指出它,因为它是一个共同的术语,
展示了在之前的章节中我们非形式化地引入了变量,这个
变量在函数部分中,我们形式化地引入了它。
    
    3.0.1  作用域和替换
    
如果一个变量在表达式的内部,这个变量对于这个
表达式来说是本地的(因而是形式化的)。如果一
个变量在表达式的外部,这个变量对于这个对于这个
表达式而言是非本地的(是形式化的或者是非形式化的)
单词本地化和非本地化的使用都是相对于一个特别的表
达式或者是一个子表达式的。

对于我们的本地的变量,如果我们总是使用名称,那么
一个替换就是要替换一个变量出现的每一处地方。但是
如果我们要重用一个名称,我们需要更加小心。这是一
个例子,使用了空格来表示不感兴趣的部分。
<x→ x <x→  x > x > 3
变量x被引入了两次:在内部的域中被引入了一次,
即使在外部的域中也引入了一次。在内部的作用域中,
x被引入了。在外部的作用域中,是一个函数,它被
应用于3. 假定3在它的作用域中,应用公理说,这个
表达式等价于用3替换了x后的表达式。这个意图是
用3代替函数中的x,而不是内部的作用域。这个结果如下:
= (3 <x→  x > 3 )

这里有一个更差的例子。假定x是一个非本地化的变量,并且,
我们在内部的作用域中重新的引入了它。

<y→ x y <x→  x y> x y  >x

应用公理说,对于所有的y出现的地方统统换成x.
外部的作用域引入了y变量,它出现了三次,所以三次
都被替换成了非本地化的x,作为形式参数用。但是,
内部的x,看起来是一个本地化的变量。在我们替换之前,
我们必须对内部的作用域使用重命名公理。选择一个新名z,
我们得到了:
<y→ x y <z→  z y> x y  >x
通过重命名和替换,得到了如下的表达式:
(x x <z→  z y> x x)

应用公理(对于元素 x:D) 在b中代替所有的v为x.
这给我们提供了一个形式化的代替记号。这是我们
非形式化表达的两个公理之一。(一个是变量引入,
另一个是在第5章中,关注的变量削除)因为形式化
等于写一个程序来执行代替。重命名公理写成了如
下的形式化的样子:
<v:D→b> = <w:D→ <v:D→ b>w>
并且它不需要一个公理,因为它是一个扩展的公理的实例。
f=<w:口f→ fw>
当一个域是明显的,或者当一个我们要包括x的域是明显的,
我们写<v→b>x 来表示在b中用x来代替v.例如,对形式参数x
来应用重命名公理。
<v→b>x = <w→<v→b>w>x
说的是用x代替v 与先用w代替v,再用x代替w是一样的。

猜你喜欢

转载自blog.csdn.net/gggwfn1982/article/details/130971855
今日推荐