《编程原本 》一1.7 概念

1.7 概念

如果一个过程使用了一个类型,它就会依赖于该类型的语法、语义,还有其计算基的复杂性.在语法上,它依赖于一些确定的文字量和一些具有特定名字和签名(signature)的过程的存在;其语义依赖于基过程的语义;其复杂性依赖于基过程的时间和空间复杂性.如果用另一个具有同样性质的类型取代这个类型,程序将仍然是正确的.如果不是基于具体的类型,而是基于对类型的一些要求(通过语法和语义性质描述)来设计软件部件,例如设计库过程或数据结构,一定能提高它们的可用性.我们将这样的一组要求称为一个概念(concept).类型表示类别;而概念表示类属.
要描述概念,就需要有一些处理类型的机制,包括类型属性、类型函数和类型构造符.类型属性(typeattribute)是从一个类型到一个值的映射,它描述有关类型的某种特征.类型属性的例子如C++里提供的内部类型属性

sizeof(T),一个类型的对象的对齐方式,以及一个struct 的成员个数等.如果F是一个函数式过程类型,Arity(F)返回其输入的个数.
类型函数(typefunction)是从一个类型到一个从属类型的映射.类型函数的一个例子是:从给定的“到T的指针”得到类型T.在某些情况下,定义一个带有一个附加的整数参数的带索引(indexed)类型函数可能很有用.例如定义一个类型函数,它返回一个结构类型的第i个成员的类型(从0开始计).如果F是一个函数式过程类型,类型函数Codomain(F)返回其结果的类型.如果F是一个函数式过程且i类型构造符(typeconstructor)是从一些已有类型出发构造新类型的机制.举例说,pointer(T) 是一个内部提供的类型构造符,它从一个类型T 出发返回“指向T 的指针”类型;struct 是一种内部提供的n元类型构造符;一个结构模板是一个用户定义的n元类型构造符.
如果T是一个n元类型构造符,下面用TT0,...,Tn.1表示将它应用于类型T0,...,Tn.1.一个重要例子是pair(二元组),将其应用于规范类型T0和T1,就得到了一个struct 类型pairT0,T1 ,它有一个类型为T0的成员m0和一个类型为T1的成员m1.要保证类型pairT0,T1 本身也是规范的,就要求它的相等、赋值、析构和构造操作都是基于类型T0和T1,通过按两个成员分别做的方式定义.同样的技术可以用于任何其他元组类型,例如triple(三元组).第12章将说明如何实现pairT0,T1 , 并说明更复杂的类型构造符如何维持规范性.
采用更形式化一点的说法,一个概念(concept)是对一个或多个类型的需求的一个描述,这一描述以对类型上的过程、类型属性和类型函数的存在及其相关性质的方式给出.如果某个(某些)特定类型满足这些需求,就说这一概念被这个(或这些)类型建模(modeled),或者说它们是这一概念的模型(model).要断言概念C被类型T0,...,Tn.1建模,我们写C(T0,...,Tn.1).如果任意的满足概念C. 的类型也必定满足概念C,就说概念C. 精化(re.ne)概念C.如果C. 精化C,也说C弱于C..
类型概念(typeconcept)指定义在一个类型上的一个概念.举例说,C++定义了类型概念整数类型,它被无符号整数类型和有符号整数类型精化.而STL定义了类型概念序列(sequence).前面一直用基本类型概念Regular和
5.附录B说明了怎样在C++里定义类型属性和类型函数.
FunctionalProcedure,它们对应于前面给出的非形式化定义.我们可以用标准的数学记法来形式化地定义各种概念.要定义概念C,采用的写法是
C(T0,...,Tn.1).
E0∧E1∧...
∧Ek.1
其中的.读作“按定义相等”,Ti 是形式类型参数,Ej 是概念子句.概念子句可以有如下三种形式:
1.前面已定义的概念的应用,说明相应类型参数的一个子集建模此概念.

2.类型属性、类型函数或者过程签名,建模相应概念的类型里必须有它们.过程签名的形式是f:TT.,其中T是过程的定义域而T. 是其值域.类型函数签名的形式是F:C→ C.,其定义域和值域都是概念.

  1. 基于这些类型属性、类型函数和过程表述的公理.
    我们有时也在第二类概念子句里的类型属性、类型函数或过程的签名之后包含它们的定义.这种定义的形式是x.→ F(x),其中的F是表达式.在特定模型里,这一定义可以被另一个不同的但与之协调的实现所覆盖.

举个例子,下面概念描述的是一元函数式过程:
UnaryFunction(F).
FunctionalProcedure(F)∧Arity(F)=1∧Domain:UnaryFunctionRegular

F .→ InputType(F,0)
下面概念描述的是同源的函数式过程:
HomogeneousFunction(F).FunctionalProcedure(F)

∧Arity(F)>0
∧ (.i, j ∈ N)(i,j.
∧Domain:HomogeneousFunctionRegular

F .→ InputType(F,0)
应该看到
(.F ∈ FunctionalProcedure)UnaryFunction(F)HomogeneousFunction(F)
.
抽象(abstract)过程指用类型和常量参数化的过程,带有对这些参数的要求.6 下面将为此使用函数模板和函数对象模板.参数放在template 关键字后面,类型参数用typename 引入,常量值用int 或其他整数类型名引入.对函数的需求通过requires 子句严格描述,该子句的内容是一个表达式,基于常量值、具体类型、形式参数、类型属性和类型参数的应用,值和类型的相等,相关概念,以及逻辑连接词等描述.7
这里是一个抽象过程的例子:

template<typename Op> 
requires(BinaryOperation(Op)) 
Domain(Op) square(const Domain(Op)& x, Op op) 
{ 
return op(x, x); 
}

定义域里的值可能很大,所以这里通过常量引用的方式传递该参数.操作一般说比较小(例如是函数指针或很小的函数对象),因此用值方式传递.
概念描述的是一个类型的所有对象都满足的性质,其中的前条件(precon-dition)描述特定对象的性质.举例说,一个过程可能要求它的某个参数是素数,对整数类型的这一需求就需要用一个概念描述,其中的素数性质用一个前条件描述.函数指针的类型只描述了它的签名,未描述其语义性质.例如,一个过
6.本质上具有我们所采用的形式的抽象过程出现在1930vanderWaerden[1930],基于EmmyNoether和EmilArtin的演讲,GeorgeCollins和DavidMusser20世纪60年代后期和70年代前期的论文在计算机代数的研究中使用了它们.例如可以参考Musser[1975].

7.requires子句的完整语法见附录B.

程可能要求它的一个参数是指向函数的指针,并要求函数实现的是整数上的一个可结合的二元运算.有关整数上二元运算的要求可以用一个概念描述,而函数的结合性用一个前条件描述.
为一集类型定义一个前条件,需要使用一些数学记法,例如全称和存在量词,蕴涵等.举例说,要描述整数的素数性质,用下面定义
property(N:Integer)prime:N=1)∧(.u, v ∈ N)uv=n(|u|=1∨|v|=1)n .→ (|n|..

这里的第一行引入了一些形式类型参数和它们建模的概念,第二行说明一个性质并给出其签名,第三行是描述有关的参数应满足的特定性质的谓词.
一元函数式过程的规范性可以定义如下

property(F:UnaryFunction)regularunaryfunction:Ff.→ (.f. ∈ F)(.x, x. ∈ Domain(F))(f=f. ∧ x = x.)(f(x)=f.(x.))

.
这一定义很容易扩充到n元函数:将相等的函数作用于相等的参数得到相等的结果.通过扩充,我们要求规范的抽象函数的所有实例化也都是规范的.除非另有说明,本书后面说到过程时都是指规范过程,因此下面讨论中将不明确写出这一前条件.
项目
1.1请将相等、赋值、赋值构造操作扩充到不同类型的对象上.请考虑两个类型的解释和联系起跨类型的过程的公理.

编程原本》提供了有关编程的一种与众不同的理解。其主旨是,实际的编程也应像其他科学和工程领域一样基于坚实的数学基础。本书展示了在实际编程语言(如C++)中实现的算法如何在最一般的数学背景中操作。例如,如何定义快速求幂算法,使之能使用任何可交换运算。使用抽象算法将能得到更高效、可靠、安全和经济的软件。 这不是一本很容易读的书,它也不是能提升你的编程技能的秘诀和技巧汇编。本书的价值是更根本性的,其终极目标是提升你对编程的洞察力。要想从中大获裨益,你需要从头到尾认真学习:阅读代码,证明引理,完成练习。到结束之时,你将看到如何把这里讨论的演绎方法应用到你的程序中,保证你做出的软件部件能一起工作,并表现出它们所应该表现的行为。 书中给出的算法和需求针对某些被操作的类型。有关这些描述的代码(也可以通过Web得到)采用C++的一个小子集书写,这样做是为了让所有有经验的程序员都能理解。这个小子集可以看做一种特殊语言,是由Sean Parent和Bjarne Stroustrup一起设计的。 无论你是一位软件开发者,还是其他以编程作为一项重要活动的专业人员,或者是一名在校的学生,你都会逐渐理解本书的经验丰富的作者多年来一直在教授和阐释的道理:数学对于编程是绝好的东西,理论对于实际是绝好的东西。
本书将演绎方法应用于程序设计,讨论程序与保证它们能正确工作的抽象数学理论之间的联系。书中把理论的规程、基于这些理论写出的算法,以及描述算法性质的引理和定理一起呈现给读者。 第1章 基础 1 1.1 理念范畴:实体,类别,类属 1 1.2 值 2 1.3 对象 4 1.4 过程 6 1.5 规范类型 7 1.6 规范过程 8 1.7 概念 10 1.8 总结 14 第2章 变换及其轨道 15 2.1 变换 15 2.2 轨道 18 2.3 碰撞点 21 2.4 轨道规模的度量 27 2.5 动作 28 2.6 总结 29 第3章 可结合运算 31 3.1 可结合性 31 3.2 计算乘幂 32 3.3 程序变换 35 3.4 处理特殊情况的过程 40 3.5 参数化算法 43 3.6 线性递归 44 3.7 累积过程 47 3.8 总结 48 第4章 线性序 49 4.1 关系的分类 49 4.2 全序和弱序 51 4.3 按序选取 52 4.4 自然全序 62 4.5 派生过程组 63 4.6 按序选取过程的扩展 63 4.7 总结 64 第5章 有序代数结构 65 5.1 基本代数结构 65 5.2 有序代数结构 70 5.3 求余 72 5.4 最大公因子 76 5.5 广义gcd 79 5.6 Steingcd 81 5.7 商 82 5.8 负量的商和余数 84 5.9 概念及其模型 87 5.10 计算机整数类型 88 5.11 结论 89 第6章 迭代器 91 6.1 可读性 91 6.2 迭代器 92 6.3 范围 94 6.4 可读范围 97 6.5 递增的范围 106 6.6 前向迭代器 108 6.7 索引迭代器 113 6.8 双向迭代器 114 6.9 随机访问迭代器 115 6.10 总结 117 第7章 坐标结构 119 7.1 二叉坐标 119 7.2 双向二叉坐标 123 7.3 坐标结构 129 7.4 同构,等价和有序 129 7.5 总结 137 第8章 后继可变的坐标 139 8.1 链接迭代器 139 8.2 链接重整 140 8.3 链接重整的应用 147 8.4 链接的二叉坐标 151 8.5 结论 155 第9章 拷贝 157 9.1 可写性 157 9.2 基于位置的拷贝 159 9.3 基于谓词的拷贝 166 9.4 范围的交换 174 9.5 总结 178 第10章 重整 179 10.1 置换 179 10.2 重整 182 10.3 反转算法 184 10.4 轮换算法 188 10.5 算法选择 196 10.6 总结 200 第11章 划分和归并 201 11.1 划分 201 11.2 平衡的归约 207 11.3 归并 212 11.4 总结 218 第12章 复合对象 219 12.1 简单复合对象 219 12.2 动态序列 227 12.3 基础类型 233 12.4 总结 236 跋 237 附录 A 数学表示 241 附录B 程序设计语言 243 参考文献 253 索引 257
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值