没有合适的资源?快使用搜索试试~ 我知道了~
理论计算机科学电子笔记160(2006)291-304www.elsevier.com/locate/entcs基于程序切片的组件识别努诺湾Rodrigues罗德里格斯1,2DepartamentodeInforma'ticaUniversidade do MinhoBraga,Portugal卢修斯山Barbosa巴博萨1,3DepartamentodeInforma'ticaUniversidade do MinhoBraga,Portugal摘要本文报告了函数程序的特定切片技术的发展及其用于从单片代码中识别可能的连贯组件的用途。还介绍了一个相关的工具。这篇研究是一个更广泛的项目的一部分,该项目是关于由形式化方法支持的遗留代码的关键词:程序切片,静态分析,组件识别。1介绍系统再工程中的一个基本问题是识别提供重复使用服务的代码的一致性单元。通常围绕数据结构或相互关联的功能的集合组织的这样的单元可以围绕接口包装,并且可以作为原始系统的模块化架构重构中的软件组件而可用。此外,它们可以在不同的上下文中重用本文提出了使用软件切片技术来支持这样一个组件的识别过程。[16,14,15]由魏泽在后期1本文报告的研究得到了FCT的支持,合同号为POSI/ICHS/44304/2002,PURE项目的背景2电子邮件:nfr@di.uminho.pt3电子邮件:lsb@di.uminho.pt1571-0661 © 2006 Elsevier B.V. 在CC BY-NC-ND许可下开放访问。doi:10.1016/j.entcs.2006.05.029292N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)29170年代,程序切片是一系列技术,用于隔离程序中依赖于或依赖于特定计算实体的部分。作为切片标准。因此,它在服务或组件识别方面的潜力是非常明显的。但实际上,这需要• 对切片标准所理解的内容的一个灵活定义。事实上,威瑟最初的定义已经被修改和扩展了好几次,导致了定义和计算程序片的不同方法的出现。尽管存在这种多样性,但大多数方法和相应的工具都以命令式或面向对象的范例为目标,其中相对于变量或程序语句来计算程序切片。• 提取实际(可执行)代码片段的能力• 当然,还有合适的工具支持。所有这些问题都在本文中得到解决。然而,我们的注意力仅限于函数式程序[2]。这样的关注不仅可以解释下面提到的研究背景,而且还因为我们故意想采取一种替代方法来主流研究切片,其中函数式编程在很大程度上被忽视了。因此,我们的研究问题包括定义什么是函数式程序的切片,如何提取和表示程序数据,从函数式单片代码中识别组件的最合适标准是什么。在我们的标题中还有另一个对限定泛函的解释:支持设想方法的工具完全是在HASKELL中开发的[2]。这项研究的背景是一个关于程序理解的更广泛的项目,由正式方法支持的遗留代码的再工程项目中的许多案例研究都涉及功能代码,甚至是可执行规范的形式。实际上,如果正向软件工程今天可以被视为正式方法的一个失去的机会(在安全关键和可靠计算等领域有明显的例外),逆向工程看起来越来越有前途的应用领域,由于工程的复杂性和指数成本。在运行软件产品的唯一质量证明仍然是生命周期耐久性的情况下,客户和软件生产商几乎没有准备修改或改进运行代码。然而,面对如此依赖遗留软件的风险,管理人员越来越愿意花费资源来增加对,对-他们的代码的理解水平。本文的组织结构如下。第2节回顾了程序切片的基本概念,介绍了函数切片,定义了一种新的表示结构--函数依赖图(FDG)和基于FDG的切片操作,第3节描述了相应的原型工具(HaSlicer)。第4节讨论了如何将这些技术和工具用于“组件展示”4.具体化的理解并不像乍看上去那么怪异。 实际上,作者意识到在软件文档的工业伙伴关系背景下遗 留 规 范的数量和相关 性。N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291293”的理解和识别。一个小的例子来说明这种方法。 本文最后一小部分是结论和未来的工作。2函数式程序切片2.1程序切片Weiser在[15]中将程序片S定义为通过删除语句从程序P获得的简化可执行程序,使得S复制P的部分可执行程序。一个互补的定义将程序切片描述为程序的片段,这些片段在该程序内部产生特定的计算结果[13]。程序切片的计算称为程序切片。这个过程是由所谓的切片标准驱动的,在大多数方法中,切片标准是一对包含行号和变量标识符的对。从用户的角度来看,这代表了代码中的一个点,他/她希望检查其对整个程序的影响从程序切片器的角度来看,切片准则被视为种子,从该种子计算程序切片。根据Weiser最初的定义,切片由一个可执行的子程序组成,包括所有对被选作切片标准的实体的值的结果有某种直接或间接后果的语句。关注的是只找到程序中的特定实体的代码片段。Weiser方法对应于现在被归类为向后的静态切片方法。一个对偶概念是由Horwitz等人[5]引入的前向切片。在前向切片中,人们感兴趣的是什么依赖于被选作切片标准的实体或被选作切片标准的实体所约束。请注意,将这两种方法结合起来也会产生有趣的结果。特别地,对于相同标准n的后向切片到前向切片的联合提供了一种在代码上的选择性窗口,其突出显示与实体n相关的区域。另一个二元性出现在静态切片和动态切片之间。在第一种情况下,只使用静态程序信息,而第二种情况下也考虑输入值[6,7],由于使用的额外信息,经常导致更小,更容易分析切片,尽管有效性有限切片技术总是基于某种形式的抽象的,基于图形的程序表示,从中可以识别和提取它操纵的实体之间的依赖关系。 因此,一般来说, 切片问题简化为关于特定节点的子图识别。然而,请注意,一般来说,切片可能会成为一个高度复杂的过程(例如,当作用于非结构化控制流结构或分布式原语时),甚至在某些情况下是不可判定的[12]。2.2函数式程序切片如上所述,程序切片的主流研究目标是命令式语言,因此,它面向特定的,良好表征的计算变量,程序语句和控制流行为的概念。294N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291⊆×.对函数式程序进行切片需要不同的视角。函数,而不是程序语句,是基本的计算单位,函数组合取代了语句排序。 此外,没有任何可赋值变量或全局状态的概念。此外,在现代函数式语言中,封装结构,如HASKELL[2]模块或ML[4]抽象数据类型,提供了强大的结构化机制,在程序理解中不可忽视。那么对于函数式程序来说,什么是合适的切片概念呢?更具体地说:适用于组件识别过程?这就是本节提出的问题。2.3函数依赖图如上所述,切片技术总是基于某种依赖图。典型的这样的结构是控制流程图(CFG)和程序依赖图(PDG)。对于程序P,CFG是一个有向图,其中每个节点与来自P的语句相关联,并且边表示语句之间的控制流这类图完全依赖于程序语句的精确概念由于函数式语言是基于表达式而不是语句,因此CFGPDG是一个有向图,其中节点表示源代码中不同类型的实体,边表示不同类型的依赖关系。填充节点的实体可以表示函数、模块、数据类型、程序语句以及可以在代码中找到的其他种类的程序结构。在PDG中,存在不同种类的边(例如,循环承载的下行边、循环无关的下行边、控制依赖性边等),每个表示介入节点之间的不同类型的依赖性将PDG的定义适应这导致了以下定义。定义1(函数依赖图)函数依赖图(FDG)是一个有向图,G=(E,N),其中N是一组节点,ENN表示为节点之间的二元关系的一组边。 节点N =(t,s,d)由NType类型的节点类型t、SrcLoc类型的源代码位置s和Descr类型的描述d组成。源代码位置只是实际源代码中节点内容的索引。定义2(SrcLoc)类型SrcLoc是由源组成的产品文件名和特定程序元素的行 - 列 代 码 坐 标 , 即 , SrcLoc= SrcFileName × SrcBgnLine×SrcBgnColumn × SrcEndLine ×SrcEndColumn更有趣的是定义一个节点类型,它捕获信息N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291295这是上述多样性的基础,也是五龙灵活性的基石定义3(NType)FDG节点的类型由以下文字的N类型= N m(模数)|N f(函数)| N dt(数据 类型)|N c(constructor)| N d(析构函数)让我们详细解释这些类型背后的直觉节点承载Nm(模块)类型,代表软件模块,从程序分析的角度来看,对应于源代码的最高抽象级别。请注意,HASKELL对模有一个具体的定义,这使得Nm个节点的识别变得简单。模块封装了几个程序实体,特别是产生其他FDG节点的代码片段。因此,Nm节点依赖于表示模块内部定义的实体的每一个其他节点,以及对应于它可以导入的模块的节点类型N f的节点表示函数,即将某种输入信息(最终为空)转换为输出(最终也为空)的过程的抽象。函数是函数式程序的构建块,在大多数情况下,函数式程序用合适的类型信息装饰它们,使提取变得简单。更复杂的任务是将函数节点与其主体中的计算实体相对应的节点相关联-数据类型引用,其他函数或我们下面称之为函数语句。构造函数节点(Nc)专门针对具有明确类型构造函数(例如与数据类型相关联的构造函数)概念的HASKELL中的声明)。析构函数节点(Nd)存储数据类型选择器,它与构造函数是对偶的,并且再次特定于函数范式5。FDG中的这种节点多样性通过弧互连。 在所有情况下,从节点n1到节点n2的边证明了n2对n1的依赖关系。然而,这种关系的语义取决于两个节点的类型。例如,从Nf(函数)节点n1到Nm(模块)节点n2的边意味着由n2表示的模块依赖于与n1相关联的函数,即特别是,n1中的函数定义在n2中的模内。另一方面,从节点n3到n4的边,都是Nf类型,见证了n4中的函数对n3中的函数的依赖性。这意味着,特别是,后者被前者称为。注意与Nm,Nf情况的区别,其中依赖性意味着模块内部的定义。表1介绍了边相对于它们连接的节点类型的预期语义。还要注意,FDG仅表示直接依赖关系。例如,FDG中没有节点可以证明模块使用了在其他地方定义的函数。在这种情况下所代表的是一种关系[5]然而,在其他情况下也可以找到类似的概念,例如:C选择器操作符“。“从结构构造中检索指定字段。面向对象的语言也有等价的选择器操作符。296N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291目标NType源NType边缘语义NmNm{Nm}{Nf,Nc,Nd,Ndt}目标节点导入源节点源节点包含目标节点定义NfNf{Nst}{Nc,Nd,Ndt,Nf}语句属于函数定义函数正在使用目标节点功能Ndt{Ndt}源数据类型正在使用目标数据类型Ndt{Nc}数据类型由目标节点构造Ndt{Nd}数据类型被目标节点析构表1FDG边缘描述在外部函数和调用它的内部函数之间。从那里可以通过特定的切片标准来检索间接依赖2.4切片过程基于函数依赖图的程序切片是一个五阶段的过程,如图1所示。 正如预期的那样,第一阶段对应于解析 源代码,给出抽象语法树(AST)实例t的起源。接下来是一个抽象过程,从t中提取相关信息,根据找到的不同类型的节点构建FDG实例g第三阶段是实际切片发生的地方。这里,给定一个切片标准,由来自t的节点和特定的切片算法组成,原始FDGg被切片,产生g的子图gJ。注意,切片发生在FDG上,并且结果总是原始图的子图第四阶段负责基于切片图g修剪ASTt。 在这一点上,使用图gJ中不存在的每个程序实体来修剪 t中对应的语法实体,给出t的子树tJ的起源。 最后,发生代码重构,其中通过阶段1的逆过程消耗修剪的树tJ以生成切片程序在[9]中,我们称之为切片组合子的一些东西被正式定义为关系演算[1]中的运算符,在其之上实现了实际的切片算法,即上面的第三和第四阶段。这为程序切片的代数提供了基础,然而,这超出了范围这张纸。N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291297Fig. 1. 切片过程3HaSlicer原型HA SLICER6是一个完全用HASKELL编写的函数式程序的切片器原型,作为上一节讨论的概念的概念验证。包括向前、向后和向前依赖切片。一般来说,原型实现了上述切片组合器[9],并解决了组件识别的另外两个基本问题:从源代码中提取过程的定义以及在生成的FDG上引入可视化界面以支持用户交互。虽然它的当前版本只接受HASKELL代码,但其他函数式语言以及V dm-SL元语言的插件目前正在开发中图2显示了在一个小的HASKELL程序上运行的原型的两个快照。屏幕截图2(a)显示了工具中加载的整个FDG的可视化。请注意,根据表2,不同颜色的节点表示不同的程序实体类型。图2. (a)从图2中的一个节点上重新生成通过执行切片而得到的子图。(b).一旦计算出切片,用户就可以检索对应的代码。整个过程也可以用不同的标准或对象文件撤销或再次启动。6原型可在http://wiki.di.uminho.pt/wiki/bin/view/Nuno上进行测试298N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291节点颜色节点类型NmNfNdtNcNd表2 FDG边缘代码(a)(b)第(1)款图二. 用HA S切片机4组件发现和识别4.1两种方法基本上有两种方法可以使用切片技术,以及HA S切片工具, 可以在组件识别过程中使用:既可以作为手动组件识别的支持过程,也可以作为“发现”过程,在该过程中,整个系统都在搜索服务的可能位置,从而搜索潜在的本节将简要讨论这两种方法第一种方法处理通过分析和切片遗留代码的一些表示来指导的手动组件识别。在这种情况下,FDG似乎提供了一个合适的表示模型。通过它的分析,软件架构师可以容易地识别代码实体之间的所有依赖关系,并在N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291299graph.这一类别中最有趣的操作之一是通过服务进行组件标识。其思想是隔离实现整个系统的特定服务的组件。 这个过程以自上而下的方式开始,寻找提供所需服务的顶级功能。一旦找到这些函数,就从对应的FDG节点开始应用前向依赖性切片。这会产生一系列切片文件(每个顶级函数一个),必须合并在一起才能构建所需的组件。请注意,前向依赖切片收集每个顶级函数正确操作所需的所有程序实体。因此,通过合并与特定服务相对应的所有前向依赖性切片,可以得到最少的(派生的)程序 来实现它。这个过程导致了一个新组件的识别,除了在其他上下文中可重用之外,它通常是(模块化)重建的一部分原始的遗留系统。但是这样的系统应该朝着什么方向进行重组,以使用已标识的服务作为独立的组件呢?这将需要对FDG进行操作,在某种意义上,这与切片是双重的。 组成从系统中提取每个程序实体,但对于已经收集的程序实体, 在计算的切片中。这样的操作,这是,目前,只有部分支持的HA SLICER,通常产生一个程序,不能立即执行,但可以在该方向上转换。这基本上相当于在原始代码中识别潜在的中断函数调用,并将它们重定向到 新组件切片的第二个用途在本节的开头提到的“组件发现”的名称下,依赖于切片技术来自动隔离可能的组件。根据我们的经验,这在部件识别的早期阶段特别有用。然而,必须谨慎使用这些程序,因为它们可能导致识别假阳性和假阴性。这意味着可能存在未找到的组件的良好候选项,以及确定了几个可能的组件但结果缺乏任何实际或操作兴趣的情况。要使用自动组件“发现”过程,必须首先了解要查找什么,因为没有通用的方法来说明哪些特征对应于潜在的软件组件。因此,人们必须通过间接的方法来寻找组件,这当然包括识别组件通常具有的某些特性,但也包括一些过滤标准。一个值得关注的典型特征是围绕一个公共数据类型结构组织一堆函数。因此,组件“发现”的一个可能标准是基于原始代码中定义的数据类型。其思想是对每一种数据类型进行隔离,并隔离该数据类型和系统中依赖于它的每个程序实体。第二个众所周知的特征,由面向对象通信识别300N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291nity,涉及到这样一个事实,即“有趣的”组件通常呈现出低水平一个高层次的凝聚力和耦合[18]。简单地说,耦合是评估两个组件相互依赖程度的度量,即。它试图测量一个组件中的变化对系统中其他组件的影响程度。另一方面,内聚度量特定组件的功能之间的内部关联程度。通常,在具有低内聚度的组件中,难以检测错误和不期望的错误。在实践中,如果它的功能是弱相关的错误可能会“隐藏”在很少使用的领域,并保持不可见的测试一段时间。这两个指标的结合导致了一个“发现”标准,该标准使用FDG来寻找特定的功能集群,即强相关函数的集合,减少了对该集合之外的任何其他程序实体的依赖性。这样的函数簇不能通过程序切片技术来识别,但是FDG在确定这些聚类时仍然非常有用。事实上,这些类型的度量可以在FDG中表示的信息之上计算。 特别是,HASLICER工具通过以下方式计算它们的组合值:联轴器(G,f){(x,y)|1996年,yGx<$x∈ f<$y/∈f}(1)内聚力(G,f){(x,y)|1996年,yGx<$x∈ f<$y∈f}(2)CCAnalysis(G) {(Coupling(G,f), Cohe sin(G,f))|{f∈P}(3)其中G是FDG,F是一组被仔细检查的函数。根据人们希望组件发现标准的自由或严格程度,可以使用耦合和内聚的不同接受限制。这将定义哪些集群将被视为潜在组件的轨迹。一旦识别出这样的集群,该过程继续对集群中的每个函数应用前向依赖切片并合并结果代码。4.2玩具的例子为了说明切片在组件识别中的应用,考虑附录A中显示的玩具银行账户系统的HASKELL代码。相应的FDG,如图3所示。如果有人尝试将自动组件“发现”方法应用于此代码,例如,基于组合的内聚耦合度量,则要考虑的情况的数量很快就会变得非常大。这是因为算法在函数集上迭代powerset。然而,一个简单的过滤器基于耦合,凝聚力和基数的分析下的集合大大减少了考虑的情况。这个想法是调整“发现”引擎,以寻找高内聚值与低耦合值的组合,最重要的是,减少分析集中的元素数量。将这种滤波器应用于手头的例子的结果再现在表3中。显然,已经确定了两个组件(对应于图3中FDG的灰色区域):一个用于处理客户信息的组件,另一个用于管理帐户数据。如上所述,这一进程将继续进行,N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291301图三. 玩具银行账户系统职能COHCougetAccAmount findAcc existsAcc insertAcc updateAcc removeAcc70getCltName findClt existsClt insertClt updateClt removeClt70表3实施例3的内聚和耦合度量在与所识别的集合中的函数相对应的节点上应用前向依赖切片,然后进行切片合并。5相关工作在我们的方法中使用的FDG定义与Ottero和Ottero在[8]中定义的程序依赖图的概念密切相关,尽管我们已经专门化了该图以面向函数范式并为节点关系引入了新的语义。我们的组件识别方法基于Schwanke等人[11] [10]首次提出的思想,其中耦合和凝聚等设计原则用于识别高度凝聚的模块。在这里,我们偏离现有的方法,通过利用HASKELL的懒惰属性,以便在可接受的时间内获得答案。我们的组件识别方法与其他技术之间的第二个区别,通常包括在软件集群的边界学科中[17],是我们使用的函数式语言除了模块本身之外没有聚合单元。与此相反,大多数软件集群302N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291算法是面向对象的范例,因此,它们通常基于类的概念,而类本身就是一个聚合结构。因此,我们必须处理一个小得多的编程单元的粒度模块化。6结论和今后的工作在函数切片的总体座右铭下,本文的目的是双重的。一方面,引入了一种特殊的依赖图结构FDG 作为功能切片的核心图结构,并开发了相应的原型系统。另一方面,它显示了如何切片技术可以用来识别软件组件从(功能)遗留代码,无论是作为一个支持工具的工作软件架构师或在一个自动的方式在一个过程中的组件“发现”。后者作为再工程过程早期阶段的体系结构理解技术是什么让FDG一个合适的结构,我们的目的是引入了一个本体的节点类型和diffuerentiated边缘语义。 这使得可以 以在单个结构中捕获程序可能拥有的不同抽象级别。通过这种方式,FDG不仅可以捕获软件项目的高级视图(例如,,模块或数据类型如何相关),而且还有低级别视图(下至函数体内函数语句之间的关系此外,由于不同的程序抽象级别存储在一个结构中,因此可以根据分析师的需要轻松地跳过视图。最后,请注意FDG结构足够灵活,可以很容易地适应其他编程语言和范例。未来研究的一个领域是适应图聚类技术,已经在文献中,发现的组件在FDG的情况下。关于这方面,我们已经进行了一些经验与邻接矩阵算法,指出了一个显着减少的时间来计算组件的候选人。如导言所述,这项研究是一个更广泛议程的一部分。在这方面,目前的工作包括:• 将切片技术推广到软件架构级别,以便使它们不仅适用于架构规范(如[19]),而且适用于大型异构软件系统的源代码级别,即用多种语言编程并由数千行代码组成的系统。• 本文所讨论的基于切片的组件识别与其他分析技术(例如,类型重构)也基于图形分析。引用[1] R. C. Ba ckhouse和P. F. Ho ogendijk. 数据处理的关系理论要素。 InB. 莫勒,H. Partsch和S. Schuman,editors,Formal Program Development,pages 7-42. 施普林格大学注意到N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291303比较科学 (755),1993年。[2] R. 鸟.“功能 编程使用 哈斯克尔”。计算机科学系列Prentice-Hall International,1998年。[3] 菲茨杰拉德和P.G. 拉森建模系统:软件开发中的实用工具和技术。剑桥大学出版社,1998年。[4] R. Harper和K.米切尔介绍标准的MLA。技术报告,爱丁堡大学,1986年。[5] S. Horwitz,T. Reps和D.宾克利使用依赖图的过程间切片。PLDI '88:ACM SIGPLAN 1988会议记录。《编程的使用、设计和实现》,第35-46页。ACM Press,1988.[6] B. Korel和J. Laski。 动态程序切片。 信息流程Lett. ,29(3):155[7] B. Korel和J. Laski。计算机程序的动态切片。J. Syst. Softw. ,13(3):187[8] K. J. Ottern和L. M.奥特曼软件开发环境中的程序依赖图。2001年:第一届ACM SIGSOFT/SIGPLAN软件工程研讨会论文集,实用软件开发环境,第177-184页。ACM Press,1984.[9] N.罗德里格斯函数式程序切片的基础。技术报告,PURe项目报告,DI- CCTC,美国。米尼奥,2005年。[10] R. W.施旺克软件模块化再工程的智能工具。 在ICSEIEEE计算机学会出版社.[11] R. W. Schwanke和S. J·汉森使用神经网络模块化软件。马赫学习. ,15(2):137[12] A. M. Sloane和J.霍兹沃思超越传统的程序切片。软件测试与分析国际研讨会,第180-186页,加利福尼亚州圣地亚哥,1996年Press.[13] F. Tip. 程序切片技术综述。编程语言杂志,3:121[14] M. 威瑟程序切片:一种自动程序抽象方法的形式、心理和实践研究。博士论文,密歇根大学,安阿伯,1979年。[15] M. 威瑟 程序员在调试时使用切片。 Commun. ACM,25(7):446 -452,1982.[16] M. 威瑟 程序切片。 IEEE Trans. Software Eng.,10(4):352-357,1984.[17] T. A. Wiggerts。在遗留系统再模块化中使用聚类算法。在WCREIEEE计算机协会。[18] E. Yourdon和L.康斯坦丁结构化设计:计算机程序和系统设计学科的基础。普伦蒂斯-霍尔,1979年。[19] J. Zhao. 切片技术在软件体系结构中的应用。在Proc. of 4th IEEE International Conferencei on Engineeringof Complex Computer Systems,第87-98页一个玩具银行账户系统模块Slicing whereimport MpidataSystem = Sys { clients:: [Client],accounts:: [Account] }派生显示data Client= Clt {cltid::CltId,名称 ::CltName}派生显示数据帐户=访问{ accid *AccId,amount::Amount}派生显示typeCltId=Inttype CltName =Stringtype AccId =Int typeAmount = Double304N.F. 罗德里格斯Barbosa/Electronic Notes in Theoretical Computer Science 160(2006)291initClts::[((CltId,CltName),(AccId,Amount))] -> System initClts =(uncurry Sys). split(map((uncurry Clt). fst))(map((uncurry Acc). ( snd))findClt:: CltId ->System->Maybe ClientfindClt cid sys=if(existsClt cid sys)then Just. 头filter((cid==). cltid)。客户端$sys else无findAcc:: AccId -> System -> Maybe AccountfindAccacid sys =if(existsAcc acid sys)then Just. 头filter((acid ==). accid)。accounts$ sys else无existsClt:: CltId ->System->Bool存在的,存在的,存在的地图cltid.客户existsAcc:: AccId -> System -> Bool存在Acc酸= elem酸。map accid.账户insertClt::(CltId,CltName)->System->SysteminsertClt(cid,cname)(Sysclts accs)=如果(existsClt cid(Sys clts accs)),则出现错误“客户端ID已存在!“elseSys((Clt cidcname): clts)accsinsertAcc::(AccId,Amount)-> System ->System insertAcc(acid, amount)(Syscltsaccs)=如果(existsAcc acid(Sys clts accs)),则错误“帐户ID已存在!“否则Sysclts((Acc酸量):accs)removeClt:: CltId -> System -> SystemremoveClt cid(Sysclts accs)=if(existsClt cid(Sys clts accs))then Sys(filter((cid/=). cltid)clts)accs其他系统cltsaccsremoveAcc:: AccId -> System -> SystemremoveAccacid(Sysclts accs) =if(existsAcc acid(Sys clts accs))thenSysclts(filter((acid /=). accid)accs)其他系统cltsaccsupdateClt::(CltId, CltName)-> System ->System updateClt(cid, cname)sys =if(existsClt cid sys)then insertClt(cid,cname). removeCltcid$syselse insertClt(cid,cname)sysupdateAcc::(AccId,Amount)-> System -> SystemupdateAcc(acid, amount)sys =if(existsAcc acidsys)then insertAcc(acid,amount). removeAcc acid $syselse insertAcc(acid,amount)sysgetCltName:: CltId -> System ->MaybeCltName getCltName cid sys= case findClt cid sysof只是clt ->只是。name $clt无->无getAccAmount:: AccId -> System -> MaybeAmount getAccAmount acid sys = case findAcc acidsys ofJust--Just。金额$ acc无->无
下载后可阅读完整内容,剩余1页未读,立即下载
cpongm
- 粉丝: 5
- 资源: 2万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- C++多态实现机制详解:虚函数与早期绑定
- Java多线程与异常处理详解
- 校园导游系统:无向图实现最短路径探索
- SQL2005彻底删除指南:避免重装失败
- GTD时间管理法:提升效率与组织生活的关键
- Python进制转换全攻略:从10进制到16进制
- 商丘物流业区位优势探究:发展战略与机遇
- C语言实训:简单计算器程序设计
- Oracle SQL命令大全:用户管理、权限操作与查询
- Struts2配置详解与示例
- C#编程规范与最佳实践
- C语言面试常见问题解析
- 超声波测距技术详解:电路与程序设计
- 反激开关电源设计:UC3844与TL431优化稳压
- Cisco路由器配置全攻略
- SQLServer 2005 CTE递归教程:创建员工层级结构
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功