没有合适的资源?快使用搜索试试~ 我知道了~
176理论计算机科学电子笔记64(2002)网址:http://www.elsevier.nl/locate/entcs/volume64.html19页并发声明式程序设计RachidEchahed和WendelinSerweEscheratoireLEIBNIZ{Institut IMAG,CNRS46,avenue F Viallet,F-38031 Grenoble,France电话:(+33)4 76 57 48 91;传真:(+33)4 76 5746 02Rachid. imag.frWendelin. imag.fr摘要在描述过程时,动作是必不可少的,因为过程的特征在于它们可以执行的动作。在本文中,我们处理的问题的定义的动作的上下文中的一个基于组件的方法并发声明式编程。在这种计算模型中,系统由一组交互组件建模,其中每个组件由一个称为存储的声明性程序和一组进程组成。我们给rst的并发声明式编程所考虑的计算模型的概述。在第二步中,我们建议将动作定义为从声明性程序到它们自己的函数,使用元语言,其中声明性程序的抽象数据类型可用。我们通过几个例子来说明我们的方法,并比较我们的方法相关的工作。1介绍经典的声明性语言,即,功能、逻辑和功能逻辑语言旨在提供系统的高级描述。实际上,一个纯声明性的程序可以被看作是一个静态的理论表示,它可以用于对底层模型进行推理,例如,通过如在逻辑编程范例中求解目标或通过如在函数编程范例中简化表达式。此外,这些语言具有众所周知的良好特性,例如抽象,可读性,编译技术,证明方法等。然而,由于它们的“静态”性质,声明性语言的概念不足以捕捉真实世界应用程序的整体复杂性[31],其中需要交互性,并发性和特别是,语言必须支持不断发展的理论的“动态”。例如,使用固定日期作为值的程序必须定期更新它,记录银行账户每日变化的数据库也必须随着执行的操作而变化c 2002年由Elsevier Science B出版。诉在CC BY-NC-ND许可下开放访问。埃查赫德177在账户上更明显的是交互式应用程序的情况,因为与环境的交互(例如,其他系统或用户)自然会对理论产生影响。因此,要求这种应用程序执行动作,也就是说,修改理论演示,即,声明性程序。大多数现有的声明性语言并发扩展方法,例如[4,7,8,19,26,27,28,29],以几个内置原语的形式提供动作,专用于更新当前的理论表示:Prolog [10]中的断言和撤回,动作告诉并发约束编程(ccp,[28]),Common Lisp [30]和Scheme [1](分别为SML[24])的赋值\functions”(分别为:=),或者用于更改Erlang [4]模块代码的内置操作但不幸的是,没有一套标准的此类行为,每种语言都有自己的建议。在本文中,我们主张明确区分动作的概念,声明性语言。我们考虑的计算模型的这种设计选择旨在两者,避免需要通过扩展声明性语言的概念来编码过程和动作的概念,并允许对程序或系统描述的每个部分此外,我们表明,考虑声明性的程序作为数据ob-observina元语言允许submergent不同的现有方法建立行动的程序。事实上,如果我们将(声明性)程序视为抽象数据类型(ADT)的元素,可以被认为是在这个ADT上的元语言中定义的操作。这种方法有几个优点。首先,并发性和移动性的集成方法变得更加抽象和通用,并且可以应用于任何声明性语言,因为它不依赖于特定的内置原语,这可能是其他语言难以定义的。因此,我们获得了与从数据定义传递到抽象数据类型时相同的优势。第二,程序员可以被给予可能性来定义其自己的、应用特定的动作。一方面,这应该导致更好的结构,从而更可读和维护的代码。另一方面,定义新动作的可能性允许以直接的方式增强计算模型(事实上,为了在微积分[23]的意义上对移动性建模,我们只需要引入额外的动作new)。最后,但并非最不重要的是,程序的ADT可以用作一种\glue language允许多个组件之间的交互:事实上,为了操纵其他组件,我们需要知道它们的精确结构。因此,展示程序的ADT定义了语言的“接口”(以及因此使用语言编写的组件)更正式。本文的其余部分组织如下:下一节简要介绍了所考虑的计算模型,为并发声明式编程提供基于组件的方法。第三节介绍了定义-埃查赫德178S2S1S3p5p1p4Fp2p3Fig. 1. 系统的执行模型动作的初始化,并给出了一个程序的ADT的例子,它被用来说明第4节中动作的一些定义。与一些相关工作的比较是第5节的主题。最后,第6节结束。2一种并发声明计算模型在本节中,我们将介绍我们的计算模型的大致轮廓,一种基于组件的并发声明式编程方法。关于更多的细节,我们请读者参考[14]。我们将系统建模为一组交互组件,这些组件可以分布在网络上或驻留在单个计算机上。每个组件都将由组件名标识。在内部,组件被组织为一组过程pi,即,一个并发程序和一组公式F,即,一个传统的声明式程序,叫做store。因此,系统的执行模型类似于ccp [28]或协调语言Linda [16],可以如图1所示。进程(pi)通过修改存储进行通信,即, 通过改变,以非单调的方式,由商店描述的当前理论,例如通过简单地重新定义常数(例如,赋值)或通过增加或删除F中的公式。商店的所有变化都是行动执行的结果。因此,行动构成了构建过程的基本实体。粗略地说,动作hs; ai是一对基本动作a和表示存储F的存储名s,基本动作a将在存储F上执行。动作的例子是hs; c:=v i,将(变量)常数c(在组件s的存储中定义)的定义更改为值v和hD;(print 'hello')i在显示器D上打印字符串hello。作为对进程执行动作的补充,组件的存储可以照常使用,即,用于目标求解或表达式的求值(到规范形式)。这表明我们的计算模型是声明式编程的保守扩展,因为没有埃查赫德179F函数谓词一行动P过程我进出口组件名称图二. 程序员对组件任何进程都对应于经典意义上的声明性程序从程序员的角度来看,一个组件是由四个不同的部分,明确区分不同的概念,我们的计算模型。图2显示了这些不同的部分。除了(初始)存储或声明程序(定义函数和谓词)以及过程的定义之外,组件的特征在于,一方面,可以用于修改其存储的动作的定义,另一方面,通过其与环境的接口,也就是说,从(分别,到)其他组件导入(分别,导出)的符号除了这些部分之外,组件还有一个与之关联的邮箱,用于组件之间的交互。事实上,要在远程组件上执行的操作被发送(通过我们假设是无故障的通信网络)到其邮箱。然后由远程组件来确保这些操作的执行。因此,邮箱由实现处理,对程序员透明请注意,组件的任何部分都可能丢失。例如,纯声明性程序或组件既不需要动作、进程,也不需要与其他组件交互。这再次表明,我们的计算模型是一个保守的扩展,声明式和并发编程。在这篇论文中。我们专注于行动的定义。因此,我们在下面的小节中仅逐一简要介绍其他部分的内容。此外,我们对组件之间的通信做了一些简化的假设。例如,我们假设底层的通信网络是无故障的,也就是说,所有发送的消息最终都会按照发送的顺序到达,并且没有重复。对于本文的其余部分,我们假设读者熟悉重写的经典概念(参见,例如,[11 21])以及进程代数(参见,例如,[15])。2.1店存储是一个声明性程序,通常由一个签名来表示,声明程序中使用的不同符号,以及定义符号含义(或语义)的公式集合。为了简化演示,并且不失一般性,我们选择基于条件重写规则的语言作为本文的声明性语言的示例,埃查赫德180*遵循以建筑师为基础的纪律。请注意,本文中提出的概念也适用于更现实的,即,更复杂的语言(使用约束,定义树,高阶函数等)。定义2.1签名是一对hS;i,其中S是一组排序(包括布尔值排序),=C]D是一个(S-索引)操作族。 我们区分两种操作,即构造函数C和定义函数D。条件重写规则是三重\lhs! rhs j cond“,其中lhs和rhs1 是项,cond是布尔值项。存储F= h;Ri是一对签名和一组规则R。示例2.2使用签名S= f布尔;自然g=C = f succ:Nat! Nat; zero:Nat; true:Bool gD= f+;; mod:Nat小娜Nat;<; :Nat小娜布尔g我们可以通过以下两个规则来定义\mod”操作x mody!(<1)第一个条件:x mody!(x y)mody Jx中文(简体)2.2基本动作基本动作描述悬挂物的修改,即,说明性程序。组件的第二部分(见图2)允许程序员将基本操作定义为从一个存储到另一个存储的递归函数。这种方法在第3节中更详细地介绍,包括基本动作的定义的例子。因此,我们假设在本节的其余部分,我们被赋予一组预定的基本作用。直觉,在存储F上执行基本动作a的操作语义,用基本动作a应用于它的结果替换F(a F)。例2.3基本操作(tell r)(分别为(del r))添加(重新添加,删除)一个(无条件的)规则\r!“真”是一个“真”字,是一个“真”字。2.3过程为了描述真实世界应用程序的动态行为,组件可以包含进程的定义。在我们的计算模型中,进程被定义为进程代数的风格1lhs(respectively,rhs)代表\l left(respectively,right)h和s ide”。+埃查赫德181我我M定义2.4过程项p是符合以下语法的良类型表达式:p::=成功g)si; aii(qt1 :t n)p; pp k pp + ppp进程成功表示成功终止的进程。一个保护动作=g)s i; a ii由一个保护(即,一个布尔表达式)g和一个基本动作对序列a i和存储名西岛非正式地,storename可以被看作是组件的(符号)标识符,表示组件的存储。因此,执行保护动作意味着测试(本地)存储中的保护的有效性(即,保护可以被简化为真),并且在保护有效时,以局部原子方式执行基本动作2h; a; i的序列,也就是说,对于所有存储,与之相关联的基本动作将被原子地执行。(qt1:t n)代表对进程q的调用,其中项t i作为参数。下面将给出过程的定义和进程代数中一样,我们使用特定的操作符来组合进程,即并行(k)和顺序(;)组合,非确定性选择(+)和优先级选择()。最后一个操作符不是很常见,但我们发现有必要对不可接受非确定性的关键应用程序进行建模[2]。 工艺术语的预期含义P1P2是:“仅当进程P1不能被执行时才执行进程P2”,即, 过程P1具有比过程P2更高的先验y。过程定义旨在描述过程的行为。为了避免病理情况,需要对过程的(递归)定义进行一些限制,特别是具有无限分支度的过程。避免这种问题的常见解决方案包括要求保护过程定义(参见,例如,[15])。定义2.5过程q由以下形式:M(qx1:xn)(j;pjj=1其中(对于每个j)j是保护动作,并且pj是过程项。为了便于阅读,我们在这里省略了一些关于变量使用的正式技术条件根据定义2.5,一个进程由一组(按优先级排序)“受保护的命令”3定义,每个命令由一个受保护的动作和一个进程项组成。2滥用符号,我们在本文的其余部分称为一对hs;ai表示短(基本)动作。3我们的精神与[13]的精神相似埃查赫德182(thinkxn)(2hF;(del(stickx))i;46(stick((x+1)modn))hF;(tell(iseatingx))i(stickx)^)hF;(del(stick((x+1)mod(eatsxn)(2hF;(del(is eatingx))i;3true)hF; (tell (stickx))i;;(认为 x46hF;(tell(stick((x+1)modn)i573n))i;;57(吃X n)的n)的图3.第三章。餐饮哲学家的流程定义(位于F店)例2.6考虑“用餐哲学家”的问题。我们用两个布尔函数来模拟这种情况,这两个布尔函数必须添加到例2.2的签名中,即(stickx)和(iseatingy)。前者代表棍子x躺在桌子上的事实,而后者则是哲学家y吃饭时的真实情况。使用例2.3的(基本)动作(tell r)和(del r),我们可以通过图3的过程来模拟哲学家的行为。 因为哲学家不是在思考就是在吃,所以我们用两个过程来模拟哲学家的这两种状态,即思考和吃。当一个哲学家在思考并想开始吃东西时,必须采取一种谨慎的行动注意,守卫(stickx)^(stick((x+1)modn))确保所需的两个棍子都可用,而三埃查赫德183个(基本)行动通过删除两个棍子和添加吃哲学家来修改理论。请注意,基本操作的原子执行避免了死锁。2.4导入和导出的符号我们区分不同水平的进口(分别,出口)。例如,描述存储的声明性程序本身可以是le或模块的集合。这与存储声明或动作声明从一个组件到另一个组件的导入(分别为导出)不同。前者是一种构造(声明性)程序以形成存储的设施,而后者是组件之间交互所必需的。在本文中,我们专注于在一个单一的组件的上下文中的动作的定义。因此,我们在这里仅限于对输入和输出的符号作一个简短的、非正式的介绍。在我们的计算模型中,组件之间的交互是基于远程组件的存储上的动作的执行。因此,组件需要导入可以在其他组件的存储上执行的操作。由于这些操作采用的参数与埃查赫德184远程组件的存储,存储的相关声明必须导入排序、函数和谓词。为了避免名称冲突,声明的“名称”可以用它们所定义的组件的名称作为前缀。组件的导出声明是那些可以被其他组件使用的声明。显然,它们构成了组件声明的子集。2.5操作语义一个组件的操作语义是通过一个转换系统来定义的,转换系统的状态是由一个理论表示和一个过程项组成的对,理论表示表示存储的当前状态,过程项表示要运行的过程的当前结构。状态之间的转换是由动作的执行触发的,或者由进程触发,或者由外部环境触发,例如,当传感器必须被更新时,或者由用户通过专用的解释器进行动作。在每个状态处,可以在当前存储上使用定义底层声明性语言现行的一套规则。因此,在例2.6中,人们可能会问(正在)吃饭的哲学家。关于定义转换关系的推理规则的介绍,我们邀请感兴趣的读者参考[14]。3用户定义的操作在上一节中,我们已经看到,(基本)动作是描述过程的主要UNR成分,因为过程的每次运行都对应于一个可能的nite动作序列的执行。在这一节中,我们讨论动作的定义由进程执行的操作对存储区进行操作。请注意,当一个进程必须在某个物理设备上执行操作时,后者被视为一个组件,也就是说,被建模为数据描述的存储以及设备控制部分的进程。因此,我们被引导来定义一个动作,作为一个从一个存储到另一个存储的递归函数。定义3.1一个动作可能需要一些参数,并返回一个从一个存储到一个存储的总递归函数,即,一个动作具有以下特性action:arg_type_1->. -> arg_type_n-> store-> store其中,sortstore表示存储的ADT,sortarg_type_i表示所需参数的种类。4 Concurrent Haskell(CH)的作者也有类似的观点,当他们调用一个状态转换器Transformer时,一个IOt类型的函数(或值),一个动作[26,2.1节]。埃查赫德185显然,无论使用什么形式主义来定义动作,我们都必须确保动作遵守定义3.1的条件,即动作是一个全递归函数,并且动作的结果是一个良构的L-程序。保证这些属性的一种可能性是(在句法上)限制用于描述它们的形式主义,以保证或至少允许有效分析的定义请注意,基本操作的结果存储必须是格式良好的要求的一个特定结果是它必须是类型良好的(因为这是格式良好的存储的必要条件)。然而,对于一些基本动作5,需要动态地对存储进行类型检查(即,在动作执行的时刻)可以被避免,并且由在其执行之前对程序的静态分析来代替。 考虑赋值操作c:=v。为了得到类型良好的存储,我们必须要求常量c和项(或值)v的排序相同。这个条件可以在分析过程时检查,因为我们知道存储中所有符号和项的种类使用我们的计算模型,只要能够定义或使用修改用L编写的程序的动作,就可以将过程集成到不幸的是,程序上的动作通常不被认为是语言的基本组成部分,也不是大多数熟悉的编程语言所特有的。它们是相关语言,例如Maude [7]或Common Lisp [30]及其元对象协议[20]。在这些语言中,程序可以表示为语言本身的数据,并且这些程序可以由解释器执行。然而,即使经典编程语言不提供这样的动作,程序上的特定动作也存在,但与语言语法的“预先定义的内置”混合例如,Prolog [10]提供了\predicates的assert和retract,允许在程序中添加和删除子句。 在SML [24](分别为Scheme [1]或Common Lisp [30])中,\函数”:=(分别为setq)允许更新与\可变单元格”相关联的值。在Erlang[4]中,内置函数”load_module,delete_module和purge_module "允许将一个模块的版本替换为一个新的、已更正的版本。这些内建的动作应该在定义程序P的句子中使用,它们对P有(\side-”)效应,因此修改了程序P。换句话说,这些动作的(最后一个)参数(它表示要应用动作的程序)丢失了,因为它隐式地是“self”。对于给定语言L,有许多方法来定义程序上的动作,例如通过提供一组内置动作或通过提供允许描述L的程序上的动作的因此,这样的语言是关于L的元语言,因为L-程序5 事实上,大多数只修改存储规则的操作都具有相同的属性。埃查赫德186被认为是特定数据类型的元素。在下文中,我们通过使用类似于SML的语言来验证这些想法[24]。为了让用户定义自己的操作,存储应该表示为数据对象。回想一下,手头的语言的存储是三元组h Si;Ri,其中S是排序集合,是排序操作族,R是条件重写规则集合。我们在图4中给出了所考虑的存储6的抽象数据类型(ADT)的 签 名 的 描 述。该ADT以模块化方式定义。缺少基本数据类型(如字符串和泛型列表)的签名。排序、操作、变量、术语、规则和存储的数据类型由它们的构造函数(make?),测试人员(是吗?)和访问器(get?). 请注意,此ADT并不意味着是所考虑的声明性语言的(优化)实现。4动作的示例在本节中,我们给出一些(基本)动作7的例子及其定义。所有操作都应该返回格式良好的存储。4.1添加规则最容易定义的操作是那些只向存储的一部分添加东西的操作,例如添加规则。例如,在例2.6中,(基本)操作(tell(is eating x))添加了规则\(is eating x)!“真的”到目前的商店。显然,由于在我们的ADT示例中,存储包含一个规则列表,因此我们至少有两种不同的合理可能性来实现此操作,这取决于新规则将插入规则列表的位置,即在列表的开头或结尾。下面是前者的一个(朴素的8)规范:add_rule: rule -> store -> storeadd_rule rule store=make_store(get_sorts store)(get_操作商店)(cons rule(get_rules store))Prolog提供了两个内置的“谓词”,即asserta和assertz,它们在定义相应谓词的子句的开头(asserta)或结尾(assertz)添加一个新的子句[10,pages 44{ 47]。6 为了简单起见,图4中存储的ADT示例没有区分构造函数和定义函数。7 和前面一样,我们滥用符号,把一个基本动作简称为“动作”。8 在这个和下面的例子中,我们省略了对前置条件的检查,这是确保结果存储是格式良好的所必需的,例如检查规则参数是良好类型的。埃查赫德187ADTstore(* STORES*)make_store:排序列表->操作列表->规则列表-> store get_sorts:store ->排序列表get_operations:store ->操作列表get_rules:store ->规则列表ADT规则(* RULES*)make_rule :term ->term-> rule get_lhs:rule -> termget_rhs: rule -> termget_condition: rule -> termADTterm(* TERMS*)make_variable_term:variable-> term make_application :operation -> termlist-> term is_variable:term -> boolis_application: term -> boolget_variable: term -> variableget_operation: term ->operationget_arguments: term ->termlistADT变量(* VARIABLES*)make_variable:string->sort->variableget_variable_name:variable->stringget_variable_sort:variable->sortADT操作(* DEFINED OPERATIONS*)make_operation:string -> sort -> operationget_operation_name:operation -> stringget_operation_sort:operation -> sortADTsort(* SORTS*)make_basic_sort:string->sort make_functional_sort:sort->sort->sort见图4。 ADT商店显然,如果存储的ADT更复杂,以便实现“最优”评估策略,其中规则存储在定义树中,那么可能性将是不同的[3]。仍然存在向存储添加规则的更多可能性。考虑多次添加相同规则的情况。根据操作语义,重复规则的存在可能是重要的(注意Prolog [10]的标准并不是很精确地说明Prolog中如何处理这一点)。例如,在经典的ccp中,多次告知约束c(即,将约束c多次添加到存储中)相当于只告诉它一次[28]。因此,规则的添加可以与测试相结合,例如仅当规则还不存在于存储中时才添加规则(对等价关系取模)。埃查赫德1884.2删除规则从存储中删除规则有几种可能性程序员可能希望删除一个精确的规则,或者删除指定形式的所有规则因此,当删除一个规则时,我们应该分别测试每个规则是否应该删除。然后,不同的移除可能性将对应于不同的测试,这可能是动作的功能参数。这样的测试的例子是恒等式,恒等式直到自由变量的重命名,模式匹配,union,等式(关于存储的等价性)等。removal-action的可能实现如下:remove_rules : ( rule -> bool ) -> store ->store remove_rulestest store=make_store(get_sorts store)(get_操作商店)(find_all(funx -> not(test x))规则)其中函数(find allt list)返回列表list的所有元素e的列表,其中 ( te ) 的 求 值 返 回 true 。 我 们 使 用 一 个 匿 名 函 数 ( 或 -abstraction ) 来反 转测试的 结果, 也 就是 说表 达式 ( find all(funx -> not(test x))rules)表示规则列表中所有规则r的列表,其中(test r)返回false。在Prolog中,内置的\predicate”abolish(predicate)删除给定谓词谓词的所有子句(在一个步骤中),而retract(p)删除所有可以与规则模式p统一的规则(在回溯时一个接一个)[10,pages 37 38,154 155]。虽然abolish不是很“精确”,但成功使用retract需要控制必要的回溯步骤的数量,我们认为这并不简单。4.3分配可能最常见的操作是赋值(:=),因为它在命令式编程语言中无处不在,也用于一些声明性语言,如SML [24] ,Common Lisp [30] 或Oz[29]。类似于协调语言Linda [16,page 98]中赋值的观点,我们将赋值c:=v看作是删除所有定义(常量)操作c的规则,并添加一个将c重新定义为值v的规则。因此,使用上面定义的动作(即,函数添加规则和删除规则),分配的动作可以定义如下:(:=):operation -> term -> store ->store(:=)操作term store=(add_规则(make_rule(make_application operation nil)term true)(remove_rules(rule模式匹配埃查赫德189(make_rule(make_application operationnil)(make_variable_term x)(make_variable_term y)商店))其中x和y是变量,true是布尔常量true,nil是空列表。规则模式匹配是实现基于模式匹配的移除9:rule_pattern_match: rule -> rule -> boolrule_pattern_match规则1规则2=(term_matches(get_lhs规则1)(get_lhs规则2))和(term_matches(get_rhs规则1)(get_rhs规则2))和(term_matches(get_condition规则1)(get_condition规则2))这里我们使用标准的模式匹配函数term matches:term_matches:term -> term -> bool(term matches term1 term2)如果term1匹配term2,则返回true。请注意,在我们的框架中,“在标准命令式编程语言的意义上”的“变量”对应于“变化的常数”:使用赋值,我们可以改变定义常数值的理论,并且在这些理论中的每一个中,值都不会改变,即,它是恒定的。赋值动作(c:=v)的另一种可能性可能将该项简化为标准形式,即,该动作可以添加一个规则,该规则定义C具有值term',其中term'是term的标准形式。4.4修改签名到目前为止,我们只考虑了商店规则的修改。 商店其他部分的改造,即,它签名也很有趣。例如,考虑一个窗口系统的实现。这样的系统需要存储关于当前显示在屏幕上的所有不同窗口的信息。粗略地说,一个描述系统当前状态的理论可能会用一个常数来模拟每个窗口。因此,当创建新窗口的请求到达时,理论必须 改变,并且需要创建与新窗口相对应的新常数。一个类似的例子是动态创建新的通信信道,这是强制性的,以便通过链路传递建模移动性,如微积分[23]。这些例子在[14]中有更详细的介绍。上述两个示例的共同之处在于,签名的丰富限于新的常量,然后可以如在经典命令式编程语言中那样通过赋值来进一步使用和修改新的常量。然而,也有一些情况下,添加一个新的操作,甚至一个新的排序可能是必要的。例如,如果一个程序必须9 我们假设和是以从左到右的顺序方式“懒惰地”计算的。埃查赫德190修改后,程序的新版本可以使用对新数据结构,特别是新数据类型的新操作。例如,如果我们想使用另一种更有效的数据结构来改变算法的实现,就会发生这种情况,例如图而不是列表。请注意,修改签名的操作在现代声明性语言的一些交互式解释器中隐式执行,只要允许定义新的全局符号,例如ocaml和SML/NJ中的let从签名中删除声明会带来更多问题。例如,从签名中删除一个操作还需要删除包含该操作的所有语句(规则),以及停止使用该操作的所有进程的执行(参见Erlang中purge_module的实现[4])。4.5复杂的动作当必须修改存储器的特定部分时,需要更复杂的操作。典型的例子是在不停止整个系统活动的情况下纠正错误,例如大型电话交换机或空中交通控制系统。为了处理这样的系统,并发函数语言Erlang [4]提供了内置函数delete_module、load_module和purge_module,它们允许用一个新的、更新的版本替换一个完整的模块(而不停止整个系统)。由于Erlang是无类型的,这也允许修改模块的签名,通过改变函数的属性,以及模块中定义的符号集。但是,人们可能会想象这样的情况:整个模块的交换过于粗粒度,而单个规则的修改就足够了。也许我们甚至需要改变某些功能的特性。考虑计算火车票价格的函数。可能存在新的、不可预测的策略,使得必须考虑客户的年龄、季节或时间段。因此,计算火车票价格的函数必须(在整个商店中)被一个新的函数取代,该函数具有一些额外的参数。这个动作(一般来说)很难(甚至不可能)使用现有声明性语言的内置动作来表达。另一个例子是芯片卡。由于卡的设计大约需要两年时间,应用程序的要求可能已经发生了因此,有可能在不需要重新设计芯片的情况下在芯片卡5相关工作正如在前面的章节中已经提到的,大多数现有的编程语言并不提供这样的程序修改操作,埃查赫德191而是作为集成到语言语法中的特殊内置原语。这些原语通常很难适应基于不同范式的语言由于这种原语的例子太多,无法全部调查,我们限制自己,只选择一些不同的种类。 当他们已经讨论了在Sect。4、我们在这里不作进一步评论例如,逻辑语言Prolog [10]提供了内置的pred-icates断言,撤回和废除,允许一个人添加(分别,删除)子句到(分别,从)一个程序(见节。4.1和4.2)。在基于ccp [28]框架的语言中,例如Oz [29],动作tell允许将约束添加到全局约束存储中(参见第4.1节)。提供分配的语言很多。除了命令式编程语言(例如, C++、Java、ada等),赋值动作可以在函数语言中找到(例如,SML或Common Lisp)或约束编程语言(例如,Oz)(见Sect.4.3)。 并发函数语言Erlang [4]提供了内置函数delete_module、load_module和purge_module,允许用户用新的模块替换一个模块,而不需要停止整个应用程序(参见第二节)。4.5)。 CML [27],Erlang[4]和Concurrent Haskell(CH)[26]提供了一个内置的原始spawn(或CH中的forkIO),其\side-ect”用于启动并发进程。经由端口的进程间通信(例如,在AKL [18,19],Oz [29]和Curry [8,17]中)使用内置的openPort创建端口和sendPort通过端口发送消息。后一个原语通过在相关流的末尾添加消息来修改程序;因此,关于流的当前末尾的信息必须保存在程序中,在发送消息时进行修改。与大多数并发声明式编程语言类似,大多数(逻辑)数据库中的状态更改方法[6]并没有明确区分动作和谓词的概念。此外,通过关注可以回滚的数据库更新,这些方法不包括所有动作,特别是操纵系统外部的物理对象的动作,例如警报器或生产机器,因为不能“回滚”发出的声音或逆转每一个机械变换。此外,所有这些内置程序都需要在执行它们的程序上运行。换句话说,所有动作都隐式地应用于存储本身,例如CH [26]中一元I/O的隐式状态参数。因此,这些语言实际上是为描述自包含的组件而设计的,因此,需要额外的工具来协调和交流用这些语言编写的组件。这种工具的一个例子是协调语言,例如,琳达[16]。在Linda中,进程通过共享元组空间进行通信,使用几个原语操作,即用于添加,读取和删除元组的原语。为了允许定义更高级别的通信方案,已经提出了可编程协调介质的想法[9]。类似于我们的AP-埃查赫德192通过这种方法,程序员可以定义在元组空间上可执行的动作。通过使用(声明性)程序而不是元组空间,我们给程序的可能性,以表达更复杂的协调结构的抽象层次上,而不需要通过元组空间操作编码这些策略。相关编程语言,例如,Maude [7]或Common Lisp [30]及其元对象协议[20]允许将程序表示为语言本身的术语。因此,语言本身可以用来定义动作,因为语言对应于它自己的元语言。在Maude中,META-LEVEL模块允许修改存储在模块数据库中的模块。 元对象原型(MOP's)[20],例如在CommonLisp [30]的对象系统中,也提供了在程序的部分上定义动作的可能性。在Java [22]中,反射被限制为关于程序的对象的发现信息,调用方法(包括用于创建新对象的构造函数)和ELD的修改。 但是,不能定义新的类或方法结合语言的解释器的实现(在语言中),例如Common Lisp的特殊运算符eval或Maude的meta-reduce,它解释其参数,reection允许编写自修改程序。这可以用来实现程序的执行方案是类似于我们的组件。然而,由于进程的定义不与存储分离,甚至进程的定义也可以动态地修改为了便于理解程序,我们倾向于将不同的事物分开,即存储和修改存储的进程。脚本语言Tcl/Tk [25]允许通过执行命令来修改表示图形用户界面(GUI)的存储。可用操作(或命令)的集合可以扩展。因此,由于其适应性和灵活性,Tcl/Tk被广泛用于构建GUI。6结论在本文中,我们介绍了如何在基于组件的并发声明式编程方法中定义动作。在这种计算模型中,动作与声明式编程的基本概念有明显的区别,并被定义为从(格式良好的)程序到自身的总递归函数,使用程序的抽象数据类型可用的元语言大多数现有的(声明性)语言都提供了作为内置原语的操作,这些原语作为语法的一部分呈现,无论何时提供。另一方面,如本文所建议的这些动作的明确定义将允许应用我们的计算模型的一般原则,以便以简单的方式扩展这些语言的过程埃查赫德193此外,除了语法和语义之外,元语言对编程语言的定义应该有助于使用不同语言的系统的组合。本文提出的并发声明式程序设计计算模型因此,有几种可能的扩展和未来的工作。例如,计算模型在其当前状态下不考虑时间的概念,尽管它在大多数控制系统的建模中很重要。我们计划研究的一个具有挑战性和有趣的问题是将我们的框架与[5]中提出的时间和声明式编程引用[1] H. Abelson等人,《算法语言方案的修订报告》。高阶和符号计算,11(1):7 {105,8月。1998年[2] J. - R.阿布里尔工业应用的形式方法,计算机科学讲义第1165卷,蒸汽锅炉控制规范问题一章,第500页。Springer Verlag,1996年。[3] S. 安 托 伊 定 义 树 。 In H.Kirchner 和 G.Levi , 编 辑 , Proceedings ofthe3rdInternational Conference on Algebras and Logic Programming(ALP1992),卷632 ofLecture Notes in Computer Science,第143页{ 157,Volterra,Sept.1992.施普林格出版社[4] 阿姆斯特朗河维尔丁角Wikstrom和M.威廉姆斯ERLANG中的并发编程。Prentice Hall,第二版,1996年。[5] J. Blanc和R.埃查赫德增加功能逻辑程序的时间电子笔记理论计算机科学,64,2002。[6] A. J. Bonner和M. 基弗变化的状态:调查。 芽孢杆菌中弗赖塔格,H. Decker,M. Kifer和A. Voronkov,编辑,《逻辑数据库中的交易和变化:逻辑数据库和变化的意义国际研讨会的邀请调查和选定论文》和《逻辑编程和演绎数据库中的(跨)动作和变化的ILPS '97会后研讨会》,(1997年),《计算机科学讲义》第1472卷,第1页,Schlo Dagstuhl和Port Je erson,1998年。施普林格出版社[7] M. Clavel,F. Duran,S. Eker,P. Lincoln,N. Mart-Oliet,J. Meseguer,和J. Quesada. Maude:Speci Cation and Programming in Rewriting Logic.计算机科学实验室,SRI国际,3月。1999年[8] Curr
下载后可阅读完整内容,剩余1页未读,立即下载
cpongm
- 粉丝: 4
- 资源: 2万+
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- zigbee-cluster-library-specification
- JSBSim Reference Manual
- c++校园超市商品信息管理系统课程设计说明书(含源代码) (2).pdf
- 建筑供配电系统相关课件.pptx
- 企业管理规章制度及管理模式.doc
- vb打开摄像头.doc
- 云计算-可信计算中认证协议改进方案.pdf
- [详细完整版]单片机编程4.ppt
- c语言常用算法.pdf
- c++经典程序代码大全.pdf
- 单片机数字时钟资料.doc
- 11项目管理前沿1.0.pptx
- 基于ssm的“魅力”繁峙宣传网站的设计与实现论文.doc
- 智慧交通综合解决方案.pptx
- 建筑防潮设计-PowerPointPresentati.pptx
- SPC统计过程控制程序.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功