首页> 中国专利> 用于声明性编程语言的基于树的有向图编程结构

用于声明性编程语言的基于树的有向图编程结构

摘要

提供了用于声明性编程语言的基于树的有向图编程结构的各实施例。在各实施例中,复杂的图结构化数据(在此在一个非限制性实现中被称为“DGraph”)是使用紧凑的人类友好的句法而不使用显式标识符来创作的。在一个非限制性方面,句法包括对遵从关系(也被称为因子分解的关系)的支持。在另一非限制性方面,半结构化图数据是基于树的表示,并且句法包括引用的词法解析或词法作用域确定和/或非局部初始化。

著录项

  • 公开/公告号CN102171679A

    专利类型发明专利

  • 公开/公告日2011-08-31

    原文格式PDF

  • 申请/专利权人 微软公司;

    申请/专利号CN200980139954.8

  • 申请日2009-09-30

  • 分类号G06F17/00(20060101);G06F9/44(20060101);

  • 代理机构31100 上海专利商标事务所有限公司;

  • 代理人陈斌

  • 地址 美国华盛顿州

  • 入库时间 2023-12-18 03:17:32

法律信息

  • 法律状态公告日

    法律状态信息

    法律状态

  • 2015-05-13

    专利权的转移 IPC(主分类):G06F17/00 变更前: 变更后: 登记生效日:20150421 申请日:20090930

    专利申请权、专利权的转移

  • 2014-07-23

    授权

    授权

  • 2011-10-12

    实质审查的生效 IPC(主分类):G06F17/00 申请日:20090930

    实质审查的生效

  • 2011-08-31

    公开

    公开

说明书

技术领域

本发明一般涉及用于声明性编程语言的基于树的有向图编程结构。

背景

作为一般背景,在计算机科学中,抽象句法树(AST)是用编程语言编写的一些源代码的句法的树表示或源代码的某一其他功能等效表示。树的每一节点表示出现在源代码中的构造。该树因不表示出现在原始源中的一些构造而是抽象的。这种省略的示例是对圆括号进行编组,因为在AST中,操作数的编组隐含在树结构中。

解析器通常将AST作为编译源代码的过程的一部分来构建。一旦构建了AST,例如语义分析等后续处理就可以向该AST添加附加信息,这可造成基于AST来产生抽象语义图(ASG)。ASG是比AST更高级的抽象,它可被用来表达表达式或程序的句法结构。在计算机科学中,ASG是被用来表示或导出用例如编程语言等形式语言编写的表达式的语义的数据结构。

ASG通常是由浓缩和抽象过程从抽象句法树构造的。例如,浓缩可以是将从其中使用变量的标识符节点起的向后指针(back-pointer)或边添加到表示该变量的声明的节点。抽象,例如,可能需要移除细节,这些细节只在解析时相关而非对语义相关。

就此,诸如XML等半结构化数据的当前表示被限于表示树结构。对于XML,表示图结构需要使用诸如XML_ID等显式引用,相对于底层图结构的表示和存储而言,这引入了复杂性并且缺乏灵活性。例如,使用XML ID需要类型系统定义标识符是什么以及引用是什么,这意味着这样的定义是在底层图结构的外部,从而引入了使用复杂性。

因此,特别需要使用紧凑的人类友好的句法而不使用显式标识符来创作复杂图结构化数据的能力。当今将半结构化程序数据表示成图的上述缺点仅旨在提供常规系统的一些问题的概览,并且不旨在是穷尽性的。常规系统的其他问题以及此处所描述的各非限制性实施例的对应的益处可以在审阅以下描述后变得更显而易见。

概述

此处提供了简化概述以帮助能够对以下更详细的描述和附图中的示例性、非限制性实施例的各方面有基本或大体的理解。然而,本概述并不旨在作为详尽的或穷尽的概观。相反,本概述的唯一目的是以简化的形式来提出与一些示例性非限制性实施例相关的一些概念,作为以下各实施例的更为详细的描述的序言。

提供了用于声明性编程语言的基于树的有向图编程结构的各实施例。在各实施例中,复杂图结构化数据(在此在一个非限制性实现中被称为“DGraph(D图)”)是使用紧凑的人类友好的句法而不使用显式标识符来创作的。在一个非限制性方面,句法包括对遵从(conformance)关系(也被称为因子分解(factored)关系)的支持。在另一非限制性方面,半结构化图数据是基于树的表示,并且句法包括引用的词法解析或词法作用域确定和/或非局部初始化。

这些和其他实施例在下面将更详细地描述。

附图简述

各非限制性实施例参考附图来进一步描述,附图中:

附图1是声明性编程语言和相关结构的编译过程链的框图;

附图2是遵从关系的一般图示;

附图3是示出有向图结构的第一非限制性方面的流程图;

附图4是示出有向图结构的第二非限制性方面的流程图;

附图5是示出根据本文描述的一个或多个方面的作为具有计算机可执行模块的计算机可读介质的示例性实施例的框图;

附图6是出于说明性目的的半结构化图数据的示例图表表示;

附图7是出于说明性目的的半结构化图数据的示例图表表示;

附图8是出于说明性目的的半结构化图数据的示例图表表示;

附图9示出结合一个或多个实施例中描述的基于树的结构的词法作用域确定的示例性方面;

附图10、11、12及13示出有向图结构的不同的词法作用域确定选择的到文本表示的图表映射,从而能对各选择进行比较;

附图14、15、16、17和18类似地示出一系列类似的或相关的有向图结构示图,用于示出用于描述图结构的紧凑且灵活的句法的附加方面;

附图19是用于声明性编程模型和相关表示的示例性过程链;

附图20是与面向记录的执行模型相关联的类型系统的图示;

附图21是根据本发明的一实施例的与基于约束的执行模型相关联的类型系统的非限制性图示;

附图22是根据有序的执行模型的数据存储的图示;

附图23是根据次序无关的执行模型的数据存储的非限制性图示;

附图24是表示其中可实现此处所描述的各实施例的示例性、非限制性联网环境的框图;以及

附图25是表示其中可实现此处所描述的各实施例的一个或多个方面的示例性、非限制性计算系统或操作环境的框图。

详细描述

概览

如以上在背景中讨论的,常规系统尤其不能允许使用紧凑的人类友好的句法来创作复杂图结构化数据。在用XML来表示复杂图结构化数据的情况下,该表示必须使用诸如XML_ID等显式标识符或引用来形成该结构化图数据。

因此,在各非限制性实施例中,提供了用于声明性编程语言的基于树的有向图编程结构的各实施例。复杂图结构化数据(在此在一些实施例中被称为“DGraph”)可以使用紧凑的人类友好的句法而不使用显式标识符来创作。在各非限制性方面,句法包括对遵从关系的支持,启用引用的词法解析(也称为词法作用域确定)和/或非局部初始化。

作为以下内容的路标,首先提供各实施例的概览,然后更详细地讨论示例性的、非限制行的任选实现及示例图和图表示来提供另外的理解。接着,结合诸如D编程语言等声明性编程语言来提供一些补充上下文。最后,阐述了其中可以部署本文描述的技术的一些示例性非限制性网络和计算环境。

一般而言,用声明性编程语言来创作源代码通常是合乎需要的,声明性编程语言通常被认为是命令性编程语言的对应物。与命令性编程语言不同,声明性编程语言允许用户写下他们想要从他们的数据得到什么,而不必指定如何针对给定的技术或平台来满足这些希望。就此,D编程语言(或简写为“D”)(可在下文中找到关于它的更多细节)是很适于紧凑且人类可理解的表示的声明性编程语言,并且有利地包括用于独立于诸如闪存、关系数据库、RAM、外部驱动器、网络驱动器等底层存储机制来创建并修改数据密集应用程序的高效构造。“D”有时也被称为“M”编程语言,但为了一致起见,在本文中不使用对M的引用。

D包括用于编写声明性源代码的高效且紧凑的句法。就此,D的编程构造还可基于为编译器所接收到的给定源代码而生成的一个或多个抽象句法树来高效地表示成半结构化图数据。另外,由于该半结构化图数据的句法的人类友好性质,在可直接指定该半结构化图数据的情况下,应用程序和开发人员不需要形成实际源代码。就此,基于一组树,或D程序的另一规范,可以形成由于句法中支持的各新颖属性而高效地表示D程序的编程构造的DGraph,这些新颖属性有助于形成对于机器以及人类可理解的较简单DGraph结构,人类基于对并不深奥的DGraph结构的文本表示(像语义图的常规文本表示一样)的视觉调查就可以理解该DGraph结构。

示出了可以表示并使用D程序的不同方式的一般框图系统在附图1的编译链中示出。例如,源代码100可由开发人员或机器直接创作。源代码100可由D编译器110来编译,所述D编译器110包括例如用于解析源代码100的D解析器120和用于形成D句法树的D句法树组件130,D句法树随后可被分析并转换成D图(DGraph)结构140。D图结构140可由开发人员直接生成,并且也可由应用程序直接生成,并且基于D图结构所支持的某些特征来以紧凑的方式表示。D图结构140可被展开到树130上并展开回源代码100,D图结构140可结合数据密集应用程序根据诸如SQL数据库查询、企业数据管理(EDM)、电子表格应用程序、图形应用程序等各领域专用用途150(即,可存储并分析数据的任何地方)被编译或半编译成对象代码。

就此,D图结构140的先前未实现的两个特征包括对遵从关系的支持和对标识符或引用的词法解析。

一般而言,如附图2所示,遵从关系220将一个模型210链接到被称作它的引用模型200的另一模型。更具体而言,本文描述的声明性编程模型的上下文中的遵从关系220指的是标识共同标记的因子分解的定义的可能性,以及加入它们以用于有向图结构的高效表示。

例如,附图3概括性地示出一个实施例中的用于将声明性编程模型的编程构造表示成有向图的方法。在300,接收包括声明性编程模型的编程构造的一组定义的有向图数据结构。在310,作出因子分解是否适用于该组定义中的某一个的判定。如果是,则在320,为便于存储或其他原因,可基于因子分解原理来组合各定义以形成一共同的等效定义,或可以将各定义拆分开(因子分解)。因子分解可适用于从存储中接收到或检索到的有向图结构,或在生成有向图结构时适用于有向图结构。

为了构建灵活且任意的有向图,将词法解析或词法作用域确定(与动态作用域确定相对)与D编程语言相结合是有利的。例如,附图4概括性地示出用于基于树表示来将声明性编程模型的编程构造表示成有向图的方法。在400,接收声明性编程语言的句法树。在410,标识了定义对一个句法树进行交叉引用的不同方式的词法作用域的指示,并随后在420,生成有向图数据结构,有向图数据结构包括基于词法作用域的至少一个指示来确定的来自两个句法树的至少一个交叉引用。词法作用域确定包括定义自顶层向底层的作用域确定是否适用或自内向外的作用域确定是否适用,并且还包括指示是当前节点还是后继节点适用于图的给定边。

在一个实施例中,如附图5概括地示出的,诸如计算机可读介质等计算机程序产品500可包括用于生成或接收表示声明性编程模型的有向图数据结构的DGraph模块510。在一个实施例中,声明性编程模型支持基于约束的类型定义并遵循次序无关的执行模型。如在第一非限制性方面中描述的,可包括因子分解模块520,以用于标识可向其应用因子分解的有向图数据结构的定义。在第二非限制性方面,在生成有向图数据结构时,DGraph模块确定适用于形成有向图数据结构的词法作用域。

基于树的有向图编程结构

如上所述,在各非限制性实施例中,提供了用于声明性编程语言的基于树的有向图编程结构。基本上,对于一些附加背景,DGraph是具有以下各项的加标记的有向图:

1.节点集合N;

2.关于N的二元关系A。A被称为有向图的弧的集合。弧是节点对。

3.标记集合1;以及

4.关于Nx1的二元关系L。L被称为有向图的标记。附图6示出被表示为图表600的示例图。使用以上形式,图的图表600可用文本表示成:

N={1,2,3,4,5,6,7,8,9,10,11,12,13}

A={(1,2),(1,3),(2,4),(2,5),(2,6),(3,7),(3,8),(3,9),(4,10),(5,11),(6,2),(7,1),(8,12),(9,13)}

l={People,Jack,Jill,Name,Age,Spouse,″Jack″,23,″Jill″,25}

L={(People,1),(Jack,2),(Jill,3),(Name,4),(Age,5),(Spouse,6),(Spouse,7),(Name,8),(Age,9),(″Jack″,10),(23,11),(″Jill″,12),(25,13)}

尽管这一文本形式很精确并且足以表示所有图,但它留下了许多将要需要的事物:

1.图的结构不像在图表中那样清楚。

2.因为14不是节点,因此句法不保证例如(1,14)这样的很好地形成的图是有效句法,但不是有效边。

3.文本具有作者必须补足的对图无关紧要的信息,尤其是节点和标记id。

此外,

4.通过将描述因子分解成可被合成的分开组件来便于创作大型的图。

考虑同一图的以下文本表示:

即使没有进一步解释,也可以在视觉上观察到这一形式的图的结构的紧凑性和清楚定义。就此,用进一步细节并参考以下一般化句法来解释D图的句法。

该句法基于块结构化编程来便于创作以上文本形式的图。句法Identifier{DGraph}具有一个标记和一个块。Identifier(标识符)表示图中用该Identifier来标记的新节点。块DGraph包含该新节点的后继节点。以下较小示例表示具有4个节点和3条边的图。

Colors{″Red″,″Blue″,″Yellow″}

如附图7的图表700所示,标记为Colors(颜色)的节点具有到标记为“Red(红)”、“Blue(蓝)”、“Yellow(黄)”的节点的3条边。

句法Identifier=DNode完全等效于

Identifier{DNode},

它是具有单个后继节点的节点。以下示例表示具有2个节点和1条边的图。

Age=23

标记为Age(年龄)的节点具有到标记为23的节点的边。以下句法表示该完全相同的图。

Age{23}

引用(Reference)是DGraph的特征,没有这一特征,DGraph更像是用XML、JavaScript对象记法(JSON)、S-Expressions等表示的树。一般而言,DGraph引用相当丰富,因为引用可以是局部或绝对的,可以检索一节点(lvalue(l值))或其后继节点(rvalue(r值)),并且可以用路径来限定。

使用DGraph,带有前导“&”的引用解析到该引用所解析到的一个或多个节点。“&”类似于C中的Ivalue(I值)。在没有“&”的情况下,引用绑定到该标记解析到的节点的一个或多个后继节点。参考附图8的图表800,以下示例具有两个引用&Jill和Name(名字)。&Jill引用绑定到节点Jill{}。Name引用绑定到Name的后继节点“Jack”。

People{Jack{Name{″Jack″},Age{23},Spouse{&Jill},Nickname=Name},Jill{}}

此外,带有前导点(例如,句点)的引用是绝对的并且匹配顶层作用域。不带有前导点的引用是局部的并且匹配标记的最内部出现。

将这一选项与“&”相组合产生了四种替换方案,这四种替换方案在附图9中概括示出并在附图10、11、12和13中个别地示出。附图9示出词法作用域确定可基于当前或后继节点来应用,并且还被应用来指定声明性编程模型的各块的自内向外还是自顶向下作用域确定。四种情况分别在附图10、11、12和13中更详细地示出,由此,基于这样的词法作用域确定选择而得到的图表表示可被比较。

附图10示出第一词法解析替换方案1000,其中中心块A没有出现点和“&”。结果,有向图的等效图表表示显得如右侧那样。

附图11示出第二词法解析替换方案1100,其中中心块A没有出现点但出现了“&”。结果,有向图的等效图表表示显得如右侧那样。

附图12示出第三词法解析替换方案1200,其中中心块A既出现了点又出现了“&”。结果,有向图的等效图表表示显得如右侧那样。

附图13示出第三词法解析替换方案1200,其中中心块A没有出现“&”但出现了点。结果,有向图的等效图表表示显得如右侧那样。如上所述,这些图表表示示出了可如何经由声明性编程构造的各块的词法作用域确定可控地且灵活地形成有向图。

对于一些示例性非限制性解析规则,

1.存在隐含的顶层作用域。

2.每一个块引入新作用域并且标记被定义在一作用域内。

3.如果同一标记在一作用域内被定义多次,则所有定义被聚在一起。

4.绝对或局部

a.带有前导点的引用是绝对的并且绑定到顶层作用域中的所有匹配标记。

b.不带有前导点的引用是局部的并且有匹配地绑定到最内部作用域中的所有匹配标记。

5.lvalue或rvalue

a.带有前导“&”的引用返回该引用所解析到的一个或多个节点。

b.不带有前导“&”的引用返回该引用所解析到的所有节点的所有后继节点。

这一算法包括各标记上的相等关系,一般而言,图不要求这一点。然而,在文本形式中,引用像是所有内部节点(具有后继节点的节点)那样是标识符。串相等性因而可被用于进行比较,但其他比较是可能的,例如大小写不敏感。

在一个非限制性实施例中,引用可能尝试在解析期间遍历自身,但这被记录成错误。因此,表达式I{I}没有意义。

对于路径(Path),运算符点‘.’查找作用域内的标记并返回其(诸)后继节点。例如,以下语句对Jack和Jill示例中的任一个都是真的:

People.Jack.Age==23

People.Jill.Name==″Jill″

一般而言,路径可以解析到多个节点。例如,路径People.Jack解析到一组节点Name、Age、Spouse(配偶)。

DGraph还有利地支持因子分解的定义,使得作为句法普通写法(long hand),节点的后继节点不必全都定义在一起。例如,考虑如下表达式。

People{

Jack{Name″Jack″,Age 23},

Jill{Name″Jill″,Age 25}

}

等效图的定义如下:

People{Jack{Name=″Jack″,Age=23}},

People{Jill{Name=″Jill″,Age=25}}

因子分解可以更进一步地执行,如下:

People{Jack{Name=″Jack″}},

People{Jack{Age=23}},

People{Jill{Name=″Jill″}},

People{Jill{Age=25}}

写在彼此附近,在DGraph的简单节点集合的上下文中,以此方式将定义进行因子分解的能力可能不显得特别有用。然而,有利的是,因子分解的定义不必位于同一处,例如存储可以是分布式的。通常,图定义非常大并且将定义分布在多个文件中的能力可以用对定义进行因子分解来实现。

图之间的等价关系定义如下。在文本表示中,每一用逗号分开的节点集合定义一个作用域。在每一作用域内,标记可以出现多次。在该文本所表示的图中,标记的每一次出现的所有后继节点都是该标记的后继节点。例如,以下表达式

x{A{},B{},C{}},x{D{},E{},F{}}

表示与

x{A{},B{},C{},D{},E{},F{}}

相同的图。

跟踪这些步骤,先前示例缩减成:

People{Jack{Name=″Jack″},

Jack{Age=23},

Jill{Name=″Jill″},

Jill{Age=25}}

随后缩减成:

People{Jack{Name=″Jack″,Age=23},

Jill{Name=″Jill″,Age=25}}

使用DGraph,在构建该图时或在使用路径表达式遍历该图时,一个实现能自由地在任何时候合成这些定义。因子分解向系统给出了将存储进行分区以及将声明进行分区的能力;然而,观察者可以与该图进行交互,如同所有定义被聚在一起一样。

这类似于双向模拟,双向模拟是状态转换系统、关联系统之间的二元关系,这些系统在一个系统模拟另一系统并且该另一系统模拟该系统的意义上以同一方式运作。直观上,如果两个系统匹配彼此的行动,则它们是双向类似的(bisimilar)。在这一意义上,观察者不能将这些系统中的每一个与另一个区分开。

对于分层和各遍(pass),要注意的是,DGraph的目的是从串中构造图,这可在多个遍或阶段中出现。基本流程是串到树到图,或反向,如附图1所示。然而,在这一框架中,对于何时解析引用以及何时在将兄弟节点的后继节点与同一标记进行合并,仍然存在一定范围的灵活性。上述示例性规范被设计成允许解析在合并之前发生,这需要一些附加的复杂性才能实现;然而,这在存储图时提供了更大的灵活性并且因此值得该实现努力。

一个单独的但却相关的问题是要在被看作DGraph的现有图上放置多少解释。例如,任何任意图可被看作DGraph。将合并推迟到访问时间允许将任意图看作是已合并的。

对于功能抽象,如上所述,DGraph在是像XML或S-Expression一样的功能数据表示:因为在该表示内定义功能抽象是合乎需要的。然而,这超出了诸如机器语言(ML)或Lisp等只处理树的标准功能编程语言。

对于显式引用,因为所写的引用在构造图时被解析,所以可任选地,这些引用可被不同地处理并被当作不同种类的边。例如,在这一模型中,非引用边形成树并且引用处于单独的一类边中,该单独的一类边可以像在“双图(bigraph)”模型中那样横切该树。

以下按非限制性的方式呈现了各种附加示例,以补充本文阐述的DGraph的各方面。如上所述,D中的基本数据抽象是加标记的有向图,例如附图14的说明性示例1400所示。

该图由加标记的节点和无序的后继节点集合组成。标记包括例如Name、Jack、People等标识符以及例如″Jack″、23、2008-02-29等文字(literal)。具有这一结构的图在本文中被称为DGraph。与常规系统不同,各图不限于树并且可包含环,如附图15的示例性有向图1500所示。

后继节点是无序的。有序数据是用各列节点以正常方式构造的。例如,列表A、B、C、D被表示为:

在后续节点的集合内,各标记(如果存在)对被标记的节点而言是唯一的,但对边不是。标记还可被省略,例如,将附图16的有向图表示1600与附图15的有向图表示1500进行比较。

图结构可以是任意的。表示和类型系统在这些图上施加结构或识别这些图上的结构。以示例性非限制性的方式,以下描述讨论两个表示和一个类型系统,但还有许多其他可能的表示和类型系统。

在本实施例中,DGraph的文本表示遵循以下上下文无关语法。

例如,附图14的图1400可用文本表示为:

People{

Jack{Name{″Jack″},Age{23}},

Jill{Name{″Jill″},Age{25}}

}

同一规范DGraph可有许多可能的文本表示。作为句法捷径,在标记(Label)只有一个后继节点时,可以使用等号‘=’。以下文本表示了与以上文本和图1400完全相同的DGraph。

People{

Jack{Name=″Jack″,Age=23},

Jill{Name=″Jill″,Age=25}

}

如上所述,对于紧凑表示,可以如下省略标记:

People{

{Name=″Jack″,Age=23},

{Name=″Jill″,Age=25}

}

虽然标记可被省略,但它们仍然是有用的。没有它们,可能只能构造有限的一族树结构图。

如上所述,DGraph支持因子分解的定义,即作为句法普通写法,节点的各后继节点不必全都一起定义,并且后继节点的每一集合定义一作用域。MemberAccess(成员访问)运算符点‘.’查找作用域内的标记并返回其(诸)后继节点。

作用域机制的另一用途是构造对图的其他部分的引用,如附图15的示例1500。以下文本表示该图:

People{

Jack{Name=″Jack″,Age=23,Spouse=Jill},

Jill{Name=″Jill″,Age=25,Spouse=Jack}

}

在被用作原子值(没有后继节点)时,标识符是对该图中的另一节点的引用。引用是使用正常词法作用域确定解析规则从最内部到最外部作用域来进行解析的。

另外,以下示例表示与上文和示例1500相同的图:

People{

Jack{Name=″Jack″,Age=23,Spouse=People.Jill},

Jill{Name=″Jill″,Age=25,Spouse=People.Jack}

}

在Jack的定义内,解析过程首先查找Jack的后继节点内的标识符Jill,因为不存在匹配的标记,所以该过程随后在Jack的前辈节点People内进行查找。在这种情况下,存在标记匹配,并且它变成Jack.Spouse和People两者的后继节点。

作为非限制性技术细节,注意,为了处理一些遮挡(masking)情况,成员访问运算符可以在没有左手操作数(例如,前缀)的情况下使用,以迫使查找从最外侧作用域开始。

例如,以下表示与以上两图和示例1500相同的图:

People{

Jack{Name=″Jack″,Age=23,Spouse=.People.Jill},

Jill{Name=″Jill″,Age=25,Spouse=.People.Jack}

}

类型系统识别(或施加)该图中的结构以便于解释。这一节定义用于DGraph的一个可能的类型系统,但存在许多其他系统,并且因而各个细节应被认为不是对总体概念的限制。给定一个用于文字的简单的类型系统SimpleType,用于类型声明的以下语法属于:

对于同构集合,该同构集合的后继节点必须是同一类型T。以下是同构集合的示例:

集合的基数用运算符?、+、*或#m..n来规定。3到7个T(包括性)的同构集合被写作T#3..7。根据以下语法,任意数量的S的同构集合被写作S*。

省略..左侧的整数会将下限定义成0。省略右手侧的整数会将上限定义成无穷大。星号‘*’将界限定义成0到无穷大。加号‘+’将界限定义成1到无穷大。问号‘?’将界限定义成0到1。

实体指定所需标记集合和它们的后继节点的类型。对于每一标记,后继节点类型可以不同。以下是实体的实例:

Jack{Name=″Jack″,Age=23}

StarWarsI{Title=″Star Wars:A New Hope″,Duration=121}

实体是由分号终止的带有可任选的类型归属(ascription)和可任选的默认值的标记的列表。声明的次序不是相关的,但所有标记是不同的。实体被如下指定:

具有两个后继节点Name和Age的实体(Entity)(其后继节点分别是类型Text(文本)和Number(数字))被写成:

{Name:Text;Age:Number;}

类型归属约束节点的后继节点,使之遵循给定类型。例如,以下是有效的类型归属:

People:{Name:Text;Age:Number;}*{

Jack{Name{″Jack″},Age{23}},

Jill{Name{″Jill″},Age{25}}

}

相反,以下是无效类型归属:

People:{City:Text;Zip:Number;}*{

Jack{Name=″Jack″,Age=23},

Jill{Name=″Jill″,Age=25}

}

与任何定义一样,节点的类型归属可被例如如下因子分解:

在D中,类型被定义为值的集合。这一集合可使用从HomogeneousCollection(同构集合)和Entity(实体)构建的类型表达式来隐式地定义。或者,图中的任何节点的后继节点定义一集合并且这也可被用作类型。考虑以下:

People:{City:Text;Zip:Number;Spouse:People;}*

这需要Spouse节点的后继节点是People节点的后继节点之一。因此,以下是有效的:

People.Jack.Spouse的后继节点是Jill。Jill是People的后继节点,所以这满足该类型。

另外,类型系统可以对图施加附加水平的解释。编译器使用这一解释来在需要时添加隐含边以满足类型约束。考虑以下示例:

这一示例类似于上面的示例。存在具有后继节点Jack的节点People。绘制这一声明的图产生了附图17的示例1700。虽然布局是不同的,但图1700几乎与图1500同构。它具有相同数量的节点。它缺少一个标记Jill以及从People到先前标记为Jill的节点的一条边。

这样,图1700不遵循关于People节点的类型归属。缺少的标记不是问题。实体上的标记是不需要的。唯一的问题是缺少的边。在这一特殊情况下,编译器可以添加边,因为类型归属需要Spouse的后继节点也是People的后继节点。

如附图18的图1800所示,这一特殊情况便于用文本表示来对嵌套图进行声明,并且启用表示捷径。有了添加的边,按实体值上的可任选标记的模来计算,两个图是同构的。

示例性的声明性编程语言

为避免疑惑,这一子节中提供的关于诸如D编程语言等声明性编程语言的附加上下文应被认为是非穷尽性的和非限制性的。以下阐述的伪码的特定示例代码段只是出于说明性和解释性的目的,并且不应被认为是对上面用各种细节描述的用于声明性编程模型的有向图结构的各实施例的限制。

在附图19中,提供了用于诸如基于D编程语言的模型等声明性模型的示例性过程链。如图所示,过程链1900可包括编译器1920、打包组件1930、同步组件1940以及多个储存库1950、1952、……、1954的耦合。在这样的实施例中,输入到编译器1920的源代码1910表示用诸如D编程语言等声明性编程语言创作的声明性执行模型。使用D编程语言,例如,源代码1910所实现的执行模型有利地遵循基于约束的类型化(typing)(即结构类型化),和/或有利地实现次序无关(即无序)的执行模型来简化代码开发。

编译器1920处理源代码1910并且可以生成每一源代码的处理后定义。虽然其他系统执行编译下至命令性格式,但源代码的声明性格式在被转换时得到保留。打包组件1930将处理后的定义打包成镜像文件,如在D编程语言的情况下是D_Image(D镜像)文件,它们可安装到特定储存库1950、1952、……、1954中。镜像文件包括必要元数据的定义和用于将多个经转换的人工产物及其声明性源模型存储在一起的可扩展存储。例如,打包组件1930可以设置特定元数据属性并将声明性源定义与编译器输出人工产物一起作为各内容部分存储在镜像文件中。

使用D编程语言,打包组件1930所使用的打包格式遵从ECMA开放打包约定(OPC)标准。本领域技术人员将容易理解,这一标准固有地提供像压缩、编组、签名等特征。这一标准还定义公共编程模型(API),它允许经由标准编程工具来操纵镜像文件。例如,在.NET框架中,API被定义在“System.IO.Packaging(系统输入输出打包)”名字空间中。

同步组件1940是可被用来管理镜像文件的工具。例如,同步组件1940可以将镜像文件当作输入并将它与一组引用的镜像文件进行链接。在这之间或之后,可以有通过提取打包的人工产物、对它们进行处理并在镜像文件中添加更多人工产物来在该同一镜像文件上操作的若干支持工具(像重写器、优化器等)。这些工具还可以操纵镜像文件的一些元数据以改变该镜像文件的状态,例如数字地签署镜像文件以确保它的完整性和安全性。

接着,部署实用程序部署该镜像文件并且安装工具将它安装到储存库1950、1952、……、1954内的正在运行的执行环境中。一旦部署了镜像文件,则它可经受各种部署后任务,包括导出、发现、服务、版本化、卸载、以及更多。使用D编程语言,打包格式提供对所有这些操作的支持,同时仍然满足企业级的工业需求,如安全性、可扩展性、可伸缩性、以及性能。在一个实施例中,储存库1950可以是关系数据库管理系统(RDBMS)的集合,然而可以容纳任何存储。

在一个实施例中,本文描述的方法可以用具有基于约束的类型系统的编程语言来操作。这样的基于约束的系统提供用传统的名义类型系统不可获得的功能。在附图13-14中,将在名义上类型化的执行系统与根据本发明的一实施例的基于约束的类型化的执行系统进行比较。如图所示,名义系统1300向每一值分配特定类型,而基于约束的系统1310中的各值可遵从无限数量的类型中的任一类型。

为了说明在名义上类型化的执行模型与根据本文描述的声明性编程语言(如D编程语言)的基于约束的类型化的模型之间的对比,用于每一模型的类型声明的示例性代码在下文中进行比较。

首先,对于在名义上类型化的执行模型,以下示例性C#代码是说明性的:

对于这一声明,存在严格的类型-值关系,其中即使A值和B值的各字段Bar和Foo的值是相同的,它们也被认为是不可比的。

相反,对于基于约束的模型,以下示例性D代码(下文中更详细地讨论)说明了对象可如何遵从多个类型:

type A{Bar:Text;Foo:Integer;}

type B{Bar:Text;Foo:Integer;}

对于这一声明,类型-值关系更加灵活,因为遵从类型A的所有值也遵从B,反之亦然。此外,基于约束的模型中的类型可以在彼此的顶部上成层,这提供了有用于跨各种RDBMS进行编程的灵活性。确实,因为基于约束的模型中的类型一开始包括全域中的所有值,所以特定值遵从所有类型,其中该值不违反该类型的声明中所编纂的约束。该组值遵从声明类型T所定义的类型。其中值<128的文本因而包括不违反“Integer(整数)”约束或“值<128”约束的“全域中的所有值”。

因而,在一个实施例中,源代码的编程语言完全是包括诸如用D编程语言实现的上述基于约束的类型系统的声明性语言。

在另一实施例中,本文描述的方法还可用于具有次序无关(即无序)的执行模型的编程语言。与上述基于约束的执行模型类似,这样的次序无关的执行模型提供有用于跨各种RDBMS进行编程的灵活性。

在附图22-23中,出于说明性的目的,根据有序的执行模型的数据存储抽象与根据次序无关的执行模型的数据存储抽象进行比较。例如,附图22的数据存储抽象2200表示根据有序的执行模型创建的列表Foo,而附图23的数据抽象2210表示根据次序无关的执行模型创建的类似列表Foo。

如图所示,数据存储抽象2200和2210中的每一个包括一组三个Bar值(即,“1”、“2”和“3”)。然而,数据存储抽象2200需要这些Bar值以特定次序输入/列出,而数据存储抽象2210没有这样的要求。相反,数据存储抽象2210仅仅向每一Bar值分配一ID,其中输入/列出这些Bar值的次序对目标储存库而言是观察不到的。例如,数据存储抽象2210可从以下次序无关的代码得到:

f:Foo*={Bar=“1”};

f:Foo*={Bar=“2”};

f:Foo*={Bar=“3”};

然而,数据存储抽象2210还可从以下代码返回:

f:Foo*={Bar=“3”};

f:Foo*={Bar=“1”};

f:Foo*={Bar=“2”};

以上两代码中的每一个在功能上等效于以下代码:

f:Foo*={{Bar=“2”},{Bar=“3”},{Bar=“1”}};

与上述基于约束的类型化和无序的执行模型相兼容的示例性的声明性语言是D编程语言,有时为方便起见在本文中也称为“D”,它是由本发明的受让人开发的。然而,除D之外,可以理解,可以使用其他类似的声明性编程语言,并且本发明的效用不限于上述有向图结构的各实施例中的任何一个或多个所适用的任何单种编程语言。就此,在下文中提供关于D的一些附加上下文。

如上所述,D是用于与数据一起工作的声明性语言。D使用户使用既适于创作又适于阅读的方便的文本句法来确定他们想要如何构造并查询他们的数据。在一个非限制性方面,D程序包括一个或多个源文件(形式上称为编译单元),其中源文件是Unicode字符的有序序列。源文件通常具有与文件系统中的文件的一对一对应关系,但这一对应关系不是必须的。为了得到最大可移植性,推荐使用UTF-8编码来对文件系统中的文件进行编码。

在概念上而言,D程序是使用以下四个步骤来编译的:1)词法分析,这将Unicode输入字符流转换成权标流(词法分析评估并执行预处理命令);2)句法分析,这将权标流转换成抽象句法树;3)语义分析,这解析抽象句法树中的所有符号,对结构进行类型检查并生成语义图;以及4)代码生成,这从语义图中生成用于某一目标运行时(例如,SQL、产生镜像)的可执行指令。另外的工具可以将镜像进行链接并将它们加载到运行时。

作为声明性语言,D不对如何存储或访问数据加以强制,也不对具体实现技术加以强制(与诸如XAML等域专用语言形成对比)。相反,D被设计成允许用户写下他们想要从他们的数据得到什么,而不必指定如何针对给定技术或平台来满足这些希望。换言之,D决不禁止各实现提供用于对在给定环境中如何表示并执行D构造进行控制的丰富的声明性或命令性支持,并且因此允许丰富的开发灵活性。

D构建在三个基本概念上:值、类型、以及范围(extent)。这三个概念可以如下定义:1)值是遵从D语言的规则的数据;2)类型描述一组值;以及3)范围向值提供动态存储。

一般而言,D将数据的类型化与该数据的存储/范围分开。给定类型可被用来描述来自多个范围的数据以及被用来描述计算的结果。这允许用户首先开始写下类型,并决定稍后将对应的值置于何处或在哪里计算该对应的值。

在确定将值置于何处的主题上,D语言不指定一实现如何将所声明的范围映射到诸如RDBMS等外部存储。然而,D被设计成使这样的实现成为可能并且与关系模型相兼容。

对于数据管理,D是不具有用于改变范围的内容的构造的功能语言,然而,D预测到范围的内容可以经由外部(对D而言)刺激而改变,并且可任选地,D可被修改以提供用于更新数据的声明性构造。

写下如何出于确认或分配的目的来对各值进行分类是合乎需要的。在D中,各个值是使用类型来分类的,其中D类型描述可接受的或遵从的(conformant)值的集合。此外,D类型被用来约束哪些值可出现在特定上下文中(例如,操作数、存储位置)。

D允许各类型被用作集合。例如,“in”运算符可被用来测试一个值是否遵从给定类型,如:

1 in Number

″Hello,world″in Text

应当注意,内建类型的名称可在D语言中直接获得。然而,也可使用类型声明来引入类型的新名称。例如,以下类型声明引入类型名称“My Text(我的文本)”作为“Text”简单类型的同义词:

type[My Text]:Text;

在这一类型名称现在可用的情况下,以下代码可被写成:

″Hello,world″in[My Text]

尽管对已有类型引入自定义名称是有用的,但对底层类型应用谓词更加有用,如:

type SmallText:Text where value.Count<7;

在该示例中,可能的“Text”值的全域被限制为包含少于7个字符的值。因此,以下语句对于该类型定义为真:

″Terse″in SmallText

!(″Verbose″in SmallText)

类型声明包括:

type TinyText:SmallText where value.Count<6;

然而,在该示例中,这一声明等效于以下声明:

type TinyText:Text where value.Count<6;

注意,类型的名称存在,使得D声明或表达式可以引用它。可以向同一类型(例如,Text where value.Count<7(值计数少于7的文本))分配任何数量的名称,并且给定值要么遵从所有这些类型要么不遵从这些类型的任一个。例如,考虑以下示例:

type A:Number where value<100;

type B:Number where value<100:

给定两个类型定义,以下表达式:

1 in A

1 in B

两者求值都将为真。如果引入以下第三类型:

type C:Number where value>0;

则可以声称下式:

1 in C

D的一般原理是给定值能遵从任何数量的类型。这偏离了许多基于对象的系统的工作方式,在这些系统中,值在初始化时被绑定到特定类型并且是在定义该类型时指定的子类型的有限集的成员。

所讨论的另一类型相关的操作是类型归属运算符(:)。该类型归属运算符断言给定值遵从特定类型。

一般而言,在看到表达式中的值时,D基于对所应用的运算符/函数的所声明的结果类型而对该值的预期类型有一点概念。例如,逻辑与运算符(&&)的结果被声明为遵从类型“Logical(逻辑)”。

对给定值应用附加约束偶尔是有用的(或甚至是需要的)——通常是为了将该值用于具有不同要求的另一上下文。例如,考虑以下类型定义:

type SuperPositive:Number where value>5;

假定存在名为“CalcIt”的函数,它被声明为接受类型为“SuperPositive(超正数)”的值作为操作数,则在D中允许以下表达式是合乎需要的:

CalcIt(20)

CalcIt(42+99)

并且禁止以下表达式是合乎需要的:

CalcIt(-1)

CalcIt(4)

事实上,D对这四个示例做的正是想要做的事。这是因为这些表达式根据常数之上的内建运算符来表达它们的操作数。确定表达式的有效性所需的所有信息在遇到表达式的D源文本时易于以很少成本来获得。

然而,如果表达式利用动态数据源和/或用户定义的函数,则使用类型归属运算符来断言某一值将遵从给定类型。

为了理解类型归属运算符如何与各值一起工作,假定第二函数“GetVowelCount(获得元音计数)”,它被声明为接受类型为“Text”的操作数并返回指示该操作数中的元音的数量的类型为“Number”的值。

因为基于“GetVowelCount”的声明不知道其结果是否将大于5,所以以下表达式不是合法的D表达式:

CalcIt(GetVowelCount(someTextVariable))

表达式是不合法的,因为“GetVowelCount”所声明的结果类型(Number)包括不遵从“CalcIt”(SuperPositive)的所声明的操作数类型的值。这一表达式可被认为是错误地编写的。

然而,这一表达式可使用类型归属运算符而被重写成以下(合法)表达式:

CalcIt((GetVowelCount(someTextVariable):SuperPositive))

通过这一表达式,D被通知到以下信息:存在对“GetVowelCount”函数的足够理解而能知道将获得遵从类型“SuperPositive”的值。简言之,程序员告诉D他/她知道D在做什么。

然而,如果程序员不知道,例如如果程序员错误地判断了“GetVowelCount”函数如何工作,则特定求值可造成负数。因为“CalcIt”函数被声明为只接受遵从“SuperPositive”的值,所以该系统将确保传递给他的所有值大于5。为了确保从不违反这一约束,该系统可以注入在求值时可能失败的动态约束测试。在D源文本被首先处理(如CalcIt(-1)的情况)时,这一失败将不发生——相反,它将在对表达式实际进行求值时发生。

就此,各个D实现通常尝试在对D文档中的第一表达式进行求值之前报告任何约束违反。这被称为静态实施,并且各实现将像句法错误一样显示这一点。然而,一些约束可只对实况数据实施,并且因此需要动态实施。

就此,D使得用户易于写下他们的意图并将该负担置于D实现上以“使它工作”。可任选地,为了允许在不同的环境中使用特定D文档,具有完全特征的D实现可被配置成拒绝以下D文档:该D文档依赖于针对正确性的动态实施以降低动态约束违反的执行和操作成本。

为了进一步提供关于D的背景,可以定义用于指定集合类型的类型构造函数。集合类型构造函数限制集合可包含的类型和元素的计数。所有集合类型是对内部类型“Collection(集合)”的限制,例如所有集合值遵从以下表达式:

{}in Collection

{1,false}in Collection

!(″Hello″in Collection)

最后示例示出集合类型不与简单类型相重叠。没有值既遵从集合类型又遵从简单类型。

集合类型构造函数指定元素的类型以及可接受的元素计数。元素计数通常是使用以下三个运算符之一来指定的:

T*-零个或更多个T

T+-一个或更多个T

T#m..n-m个T和n个T之间。

集合类型构造函数可以使用Kleene运算符或用普通写法写成对内部类型Collection的约束——即,以下类型声明描述同一集合的各值:

type SomeNumbers:Number+;

type TwoToFourNumbers:Number#2..4;

type ThreeNumbers:Number#3;

type FourOrMoreNumbers:Number#4..;

这些类型描述与以下普通写法定义相同的值集合:

与使用哪一形式来声明各类型无关,可以声称以下表达式:

集合类型构造函数与“where(其中)”运算符相组合,从而允许以下类型检查取得成功:

{1,2}in(Number where value<3)*where value.Count%2==0

注意,内部的“where”运算符应用于集合的各元素,而外部“where”运算符应用于集合自身。

正与集合类型构造函数可被用来指定什么种类的集合在给定上下文中有效一样,可以使用实体类型对实体做相同的事。

就此,实体类型声明实体值集合的预期成员。实体类型的各成员可被声明为字段或计算得到的值。对字段的值进行存储;对计算得到的值的值进行计算。实体类型是对在D标准库中定义的Entity(实体)类型的约束。

以下是简单的实体类型:

type MyEntity:Language.Entity;

类型“MyEntity(我的实体)”没有声明任何字段。在D中,实体类型是开放的,因为遵从该类型的实体值可包含其名称没有在该类型中声明的字段。因此,以下类型测试:

{X=100,Y=200}in MyEntity

求值将为真,尽管“MyEntity”类型没有提到名为X和Y的字段。

实体类型可包含一个或多个字段声明。至少,字段声明声称预期字段的名称,例如:

type Point{X;Y;}

这一类型定义描述包含至少名为X和Y的字段而不管其他字段的值的实体的集合,这意味着以下类型测试求值为真:

{X=100,Y=200}in Point

{X=100,Y=200,Z=300}in Point//比预期更多字段也是OK的

!({X=100}in Point)                //没有足够字段-不OK

{X=true,Y=″Hello,world″}in Point

最后示例示出“Point(点)”类型不约束X和Y字段的值,即允许任何值。将X和Y的值约束成数字值的新类型如下示出:

type NumericPoint{

X:Number;

Y:Number where value>0;

}

注意,类型归属句法被用来断言X和Y字段的值应当遵从类型“Number”。在这一点就位时,以下表达式求值为真:

{X=100,Y=200}in NumericPoint

{X=100,Y=200,Z=300}in NumericPoint

!({X=true,Y=″Hello,world″}in NumericPoint)

!({X=0,Y=0}in NumericPoint)

如在对简单类型的讨论中看到的,类型的名称存在,使得D声明和表达式可以引用它。这就是即使NumericPoint和Point的定义无关,以下类型测试也取得成功的原因:

{X=100,Y=200}in NumericPoint

{X=100,Y=200}in Point

D中的字段是持有各值的命名的存储单元。D允许开发人员初始化字段的值来作为实体初始化函数的一部分。然而,D不指定用于在字段的值被初始化之后改变该值的任何机制。在D中,假定对字段值的任何改变发生在D的作用域之外。

字段声明可以指示该字段存在默认值。具有默认值的字段声明不需要遵从的实体指定对应的字段(这样的字段声明有时被称为可任选字段)。例如,对于以下类型定义:

因为Z字段具有默认值,以下类型测试将成功:

{X=100,Y=200}in Point3d

此外,如果类型归属运算符被如下应用于该值:

({X=100,Y=200}:Point3d)

则,Z字段可被如下访问:

({X=100,Y=200}:Point3d).Z

在这种情况下,这一表达式将产生值-1。

在另一非限制性方面,如果字段声明不具有对应的默认值,则遵从的实体必须指定该字段的值。默认值通常是使用为“Point3d”的Z字段示出的显式句法来写下的。如果字段的类型是可空的(nullable)或者零-到-多集合,则存在隐含默认值,该默认值用于为了任选而将字段声明为空和为了集合而将字段声明为{}。

例如,考虑以下类型:

则,同样,以下类型测试将成功:

{X=100,Y=200}in PointND

并且使“PointND”归属于该值产生了这些默认值:

({X=100,Y=200}:PointND).Z==null

({X=100,Y=200}:PointND).BeyondZ=={}

选择使用零-到-1集合或可空类型对显式默认值来对可任选字段进行建模通常是由风格决定的。

计算得到的值是其值被计算而非被存储的命名表达式。声明这样的计算得到的值的类型的示例是:

注意,与以分号结束的字段声明不同,计算得到的值声明以由括号包围起来的表达式结束。

与字段声明一样,计算得到的值声明可以省略类型归属,如这一示例:

在又一非限制性方面,在没有类型被显式地归属到计算得到的值时,D可以自动地基于底层表达式的所声明的结果类型来推断该类型。在该示例中,因为在表达式中使用的逻辑与运算符被声明为返回“Logical”,所以“InMagicQuadrant”计算得到的值也被归属以产生“Logical”值。

以上定义并使用的两个计算得到的值不需要任何附加信息就能计算它们的结果而非实体值本身。计算得到的值可任选地声明当在表达式中使用该计算得到的值时其实际值必须被指定的一列命名参数。以下是需要参数的计算得到的值的示例:

为了在表达式中使用这一计算得到的值,如下提供这两个参数的值:

({X=100,Y=200}:PointPlus).WithinBounds(50)

在计算“WithinBounds”的值时,D将值50绑定到符号半径内,这使得“WithinBounds”计算得到的值求值为假。

对于D要注意,字段的计算得到的值和默认值两者都是类型定义的一部分,而不是遵从该类型的值的一部分。例如,考虑这三个类型定义:

因为RichPoint和WeirdPoint只具有两个所需字段(X和Y),所以可以如下声称:

{X=1,Y=2}in RichPoint

{X=1,Y=2}in WeirdPoint

然而,“IsHigh”计算得到的值只在这两种类型之一被归属到实体值时才可用:

({X=1,Y=2}:RichPoint).IsHigh==true

({X=1,Y=2}:WeirdPoint).IsHigh==false

因为该计算得到的值完全是该类型的一部分而非值的一部分,所以在归属被如以下串链时:

(({X=1,Y=2}:RichPoint):WeirdPoint).IsHigh==false

则最外部归属确定调用哪一函数。

至于默认值如何工作,也是按照类似原理的。还要注意,默认值是类型的一部分而非实体值的一部分。因此,在编写以下表达式时:

({X=1,Y=2}:RichPoint).Z==-1

底层实体值仍然只包含两个字段值(分别是针对X和Y的1和2)。就此,在默认值与计算得到的值不同的情况下,归属被串链。例如,考虑以下表达式:

(({X=1,Y=2}:RichPoint):WeirdPoint).Z==-1

因为首先应用“RichPoint”归属,所以所得实体具有名为Z、值为-1的字段;然而,没有向该值分配存储,即它是该值的类型解释的一部分。因此,在应用“WeirdPoint”归属时,它被应用于第一归属的结果,该结果确实具有名为Z的字段,使得值被用来指定Z的值。因而不需要“WeirdPoint”所指定的默认值。

与所有类型一样,可以使用“where”运算符将约束应用于一实体类型。考虑以下D类型定义:

type HighPoint{

X:Number;

Y:Number;

}where X<Y;

在该示例中,遵从类型“HighPoint”的所有值被保证具有小于Y值的X值。这意味着以下表达式:

{X=100,Y=200}in HighPoint

!({X=300,Y=200}in HighPoint)

两者求值都为真。

此外,对于以下类型定义:

第三类型“VisualPoint”命名了至少具有数字字段X、Y、Opacity以及DotSize的一组实体值。

因为通常需要将成员声明因子分解成可被合成的更小片段,所以D还提供对因子分解的显式句法支持。例如,“VisualPoint”类型定义可以使用以下句法来重写:

type VisualPoint:Point,Visual{

DotSize:Number;

}

为清楚起见,这是上文中使用约束表达式的普通写法定义的简略写法(shorthand)。此外,这一简略写法定义和普通写法定义两者都等效于以下更普通写法(longer-hand)定义:

同样,类型名称只是引用类型的方式——它们自身的值不记录用于描述它们的类型名称。

D还可以使用若干特征来扩展LINQ查询内涵,以使得创作简单的查询变得更简明。关键词“where”和“select”可用作二分中缀运算符。同样,索引器(indexer)被自动添加到强类型集合。如下所示,这些特征允许更紧凑地创建常见查询。

例如where作为中缀运算符,以下查询从所定义的“People”集合中提取30岁以下的人(people):

from p in People

where p.Age=30

select p

可以写出等效查询:

People where value.Age=30

“where”运算符采取左侧的集合以及右侧的布尔表达式。“where”运算符将关键词标识符值引入被绑定到该集合的每一成员的布尔表达式的作用域。所得集合包含该表达式为真的成员。由此,表达式:

Collection where Expression

等效于:

from value in Collection

where Expression

select value

D编译器在具有强类型元素的集合上添加索引器成员。对于集合“People”,例如,编译器可以添加“First(Text)”、“Last(Text)”以及“Age(Number)”的索引器。

因此,语句:

Collection.Field(Expression)

等效于:

from value in Collection

where Field==Expression

select value

“select”也可用作中缀运算符。对于以下简单查询:

from p in People

select p.First+p.Last

对该集合的每一成员计算“select”表达式并返回结果。使用中缀“select”,查询可被等效地写成:

People select value.First+value.Last

“select”运算符采取左侧的集合以及右侧的任意表达式。与“where”一样,“select”引入涉及该集合中的每一元素的关键词标识符。“select”运算符对该集合中的每一成员都映射该表达式并返回结果。又例如,语句:

Collection select Expression

等效于以下语句:

from value in Collection

select Expression

“select”运算符的平凡用途是提取单个字段:

People select value.First

编译器将访问器(accessor)添加到集合,使得单个字段可直接作为“People.First”和“People.Last”来提取。

为了编写合法的D文档,所有源文本都出现在模块定义的上下文中。模块对所定义的任何类型名称的顶层名字空间进行定义。模块还定义用于定义将存储实际值以及计算得到的值的范围的作用域。

以下是模块定义的简单示例:

在该示例中,该模块定义名为“Geometry.Point”的一个类型。这一类型描述点(point)值将看起来像什么,但不定义可存储这些值的任何位置。

这一示例还包括两个模块范围的字段(Points和Origin)模块范围的字段声明在句法中等于在实体类型中使用的那些。然而,一旦确定了范围,在实体类型中声明的字段仅仅命名可能的存储位置;相反,在模块范围声明的字段命名必须被一实现映射的实际存储位置,以加载并解释该模块。

另外,各模块可以通过使用导入命令来引用其他模块中的声明,以命名包含所引用的声明的模块。对于要由其他模块引用的声明,该声明被使用导出命令来显式地导出。

例如,考虑以下模块:

注意,只有“MyType1”和“MyExtent1”对其他模块可见,这使得“HerModule”的以下定义合法:

如该示例所示,各模块可具有循环依存关系。

D语言的类型被分成两个主要类别:本征类型和派生类型。本征类型是不能使用D语言构造来定义、而是整个在D语言规范中定义的类型。本征类型可以将至多一个本征类型命名为它的超类型来作为其规范的一部分。值是恰好一个本征类型的实例,并且遵从该一个本征类型的规范和其所有超类型。

派生类型是这样的类型:其定义是使用该语言中提供的类型构造函数在D源文本中构造的。派生类型被定义成对另一类型的约束,这创建显式子类型化(subtyping)关系。各值简单地依靠满足派生类型的约束来遵从任何数量的派生类型。值与派生类型之间没有预先附属关系——相反,遵从派生类型的约束的给定值可被随意解释成该类型。

D提供各种各样的选项来定义类型。返回一集合的任何表达式都可被声明成类型。实体和集合的类型谓词是表达式并且适合这一形式。类型声明可以显式地枚举其成员或由其他类型组成。

另一区别处于在结构上类型化的语言(如D)与在名义上类型化的语言之间。D中的类型是一组值的规范。如果完全相同的值集合遵从两种类型,则这两种类型是相同的,而不管这些类型的名称如何。不需要对要使用的类型进行命名。在需要类型引用的任何地方,都允许类型表达式。D中的类型仅仅是返回集合的表达式。

如果遵从类型A的每一值还遵从类型B,则A是B的子类(并且B是A的超类型)。子类型化是传递的,即如果A是B的子类型而B是C的子类型,则A是C的子类型(并且C是A的超类型)。子类型化是自反的,即A是A的(空)子类型(并且A是A是超类型)。

各类型被认为是满足该类型谓词的所有值的集合。出于这一原因,对集合的任何操作可被应用于类型并且类型可以与任何其他集合值那样来用表达式进行操纵。

D提供值的两个主要形成手段:计算得到的值和所存储的值(又称字段)。计算得到的值和所存储的值可以与模块和实体声明一起发生并且由它们的容器来确定范围。计算得到的值是从对表达式进行求值来导出的,该表达式通常被定义为D源文本的一部分。相反,字段存储一个值并且该字段的内容可以随时间改变。

示例性联网和分布式环境

本领域普通技术人员可以明白,此处所描述的用于声明性编程模型的有向图结构的各实施例可以结合任何计算机或其他客户机或服务器设备来实现,该任何计算机或其它客户机或服务器设备可作为计算机网络的一部分来部署或者被部署在分布式计算环境中,并且可以连接到任何种类的数据存储。就此,此处所描述的各实施例可以在具有任意数量的存储器或存储单元以及出现在任意数量的存储单元上的任意数量的应用程序和进程的任何计算机系统和环境中实现。这包括但不限于具有部署在具有远程或本地存储的网络环境或分布式计算环境中的服务器计算机和客户计算机的环境。

分布式计算通过计算设备和系统之间的通信交换提供了计算机资源和服务的共享。这些资源和服务包括信息的交换、对于诸如文件等对象的高速缓存存储和盘存储。这些资源和服务还包括多个处理单元之间的处理能力共享以便进行负载平衡、资源扩展、处理专门化,等等。分布式计算利用网络连接,从而允许客户机利用它们的集体力量来使整个企业受益。在这一点上,各种设备可具有应用、对象或资源,它们可以协作来执行本发明的各实施例中的任一个的一个或多个方面。

附图24提供了示例性的联网或分布式计算环境的示意图。该分布式计算环境包括计算对象2410、2412等以及计算对象或设备2420、2422、2424、2426、2428等,这些计算对象或设备可包括如由应用程序2430、2432、2434、2436、2438表示的程序、方法、数据存储、可编程逻辑等。可以理解,对象2410、2412等以及计算对象或设备2420、2422、2424、2426、2428等可包括不同的设备,诸如PDA、音频/视频设备、移动电话、MP3播放器、个人计算机、膝上型计算机等。

每一个对象2410、2412等以及计算对象或设备2420、2422、2424、2426、2428等可通过通信网络2440直接或间接与一个或多个其他对象2410、2412等以及计算对象或设备2420、2422、2424、2426、2428等进行通信。即使在附图24中被示为单个元件,但网络2440可包括向附图24的系统提供服务的其他计算对象或计算设备,和/或可表示未示出的多个互连网络。每一个对象2410、2412等或2420、2422、2424、2426、2428等还可包含诸如应用2430、2432、2434、2436、2438等应用,应用可利用API或适用于与根据本发明的各实施例来提供的用于声明性编程模型的有向图结构进行通信或适用于该用于声明性编程模型的有向图结构的处理或实现的其他对象、软件、固件和/或硬件。

存在支持分布式计算环境的各种系统、组件和网络配置。例如,计算系统可以由有线或无线系统、本地网络或广泛分布的网络连接在一起。当前,许多网络被耦合至因特网,后者为广泛分布的计算提供了基础结构并包含许多不同的网络,但任何网络基础结构可用于与如各实施例中所描述的用于声明性编程模型的有向图结构相关联的示例性通信。

因此,可以利用诸如客户机/服务器、对等、或混合体系结构等网络拓扑结构和网络基础结构的主机。“客户机”是使用与它无关的另一类或组的服务的一个类或组中的成员。客户机可以是进程,即大致上是请求由另一程序或进程提供的服务的一组指令或任务。客户机进程利用所请求的服务,而不必“知道”有关其他程序或服务本身的任何工作细节。

在客户机/服务器体系结构中,尤其在联网系统中,客户机通常是访问由例如服务器等另一计算机提供的共享的网络资源的计算机。在附图24的图示中,作为非限制性示例,计算机2420、2422、2424、2426、2428等可被认为是客户机而计算机2410、2412等可被认为是服务器,其中服务器2410、2412等提供数据服务,诸如从客户机计算机2420、2422、2424、2426、2428等接收数据、存储数据、处理数据、向客户机计算机2420、2422、2424、2426、2428发送数据等,但任何计算机都可取决于环境而被认为是客户机、服务器或两者。这些计算设备中的任一个可以处理数据、编码数据、查询数据、或请求可蕴含如此处对于一个或多个实施例描述的用于声明性编程模型的有向图结构的处理的服务或任务。

服务器通常是可通过诸如因特网或无线网络基础架构等远程网络或本地网络访问的远程计算机系统。客户机进程可以在第一计算机系统中活动,而服务器进程可以在第二计算机系统中活动,它们通过通信介质彼此通信,从而提供分布式功能并允许多个客户机利用服务器的信息收集能力。按照用于声明性编程模型的有向图结构的处理来利用的任何软件对象可以被单独提供或分布在多个计算设备或对象上。

在其中通信网络/总线2440是因特网的网络环境中,服务器2410、2412等可以是客户机2420、2422、2424、2426、2428等通过诸如超文本传输协议(HTTP)等多种已知协议中的任一种与其通信的web服务器。服务器2410、2412等也可担当客户机2420、2422、2424、2426、2428等,这是分布式计算环境的特性。

示例性计算设备

如上所述,有利的是,此处所描述的技术可适用于其中期望生成可快速查询大量数据的数据密集应用程序的任何设备。从而,应当理解,构想了所有种类的手持式、便携式和其他计算设备和计算对象来用于各实施例,即,在设备可能期望扫描或处理巨大量的数据来得到快速且高效的结果的任何地方。因此,以下在附图25中描述的通用远程计算机只是计算设备的一个示例。

尽管并非所需,但各实施例可以部分地经由操作系统来实现,以供设备或对象的服务开发者使用,和/或被包括在用于执行此处所描述的各实施例的一个或多个功能方面的应用软件中。软件可以在由诸如客户机工作站、服务器或其他设备等一个或多个计算机执行的诸如程序模块等计算机可执行指令的通用上下文中描述。本领域的技术人员可以理解,计算机系统具有可用于传递数据的各种配置和协议,并因此没有特定配置或协议应被认为是限制性的。

因此,附图25示出了其中可实现各实施例的一个或多个方面的合适的计算系统环境2500的一个示例,尽管如上所述,计算系统环境2500仅为合适的计算环境的一个示例,并非对使用范围或功能提出任何限制。也不应该将计算环境2500解释为对示例性操作环境2500中示出的任一组件或其组合有任何依赖性或要求。

参考附图25,用于实现一个或多个实施例的示例性远程设备包括计算机2510形式的通用计算设备。计算机2510的各组件可包括但不限于,处理单元2520、系统存储器2530、以及将包括系统存储器在内的各系统组件耦合到处理单元2520的系统总线2522。

计算机2510通常包括各种计算机可读介质,并可以是可由计算机2510访问的任何可用介质。系统存储器2530可以包括诸如只读存储器(ROM)和/或随机存取存储器(RAM)等易失性和/或非易失性存储器形式的计算机存储介质。作为示例而非限制,存储器2530还可以包括操作系统、应用程序、其他程序模块、和程序数据。

用户可以通过输入设备2540向计算机2510输入命令和信息。监视器或其他类型的显示设备也经由接口,诸如输出接口2550连接至系统总线2522。除监视器之外,计算机还可以包括其他外围输出设备,如扬声器和打印机,它们可以通过输出接口2550连接。

计算机2510可使用至一个或多个远程计算机,诸如远程计算机2570的逻辑连接在网络化或分布式环境中操作。远程计算机2570可以是个人计算机、服务器、路由器、网络PC、对等设备或其他常见网络节点、或任何其他远程媒体消费或传输设备,并且可以包括上面关于计算机2510所描述的任何或全部元件。附图25所示的逻辑连接包括诸如局域网(LAN)或广域网(WAN)等的网络2572,但也可以包括其他网络/总线。这样的联网环境在家庭、办公室、企业范围计算机网络、内联网和因特网中是常见的。

如上所述,尽管结合各种计算设备和网络体系结构描述了各示例性实施例,但基本概念可被应用于其中需要直接以机器和人类可读格式生成数据密集应用程序的任何网络系统和任何计算设备或系统,例如在大规模数据上处理查询的环境中。

而且,存在实现相同或相似功能的多种方法,例如适当的API、工具箱、驱动程序代码、操作系统、控件、独立或可下载软件对象等,它们使得应用和服务能够使用该用于声明性编程模型的有向图结构。由此,此处的各实施例从API(或其他软件对象)的观点以及从提供、生成、处理、或存储用于声明性编程模型的有向图结构的软件或硬件对象来构想。因此,此处描述的各实施例可以具有完全采用硬件、部分采用硬件并且部分采用软件、以及采用软件的方面。

在本文中使用的词语“示例性”意味着用作示例、范例或说明。为避免疑惑,本文公开的主题不受限于这样的示例。此外,本文描述为“示例性”的任何方面或设计不必解释成优于其他方面或设计或比其他方面或设计有利,它也不旨在排除本领域的普通技术人员所知的等效示例性结构和技术。而且,就术语“包括”、“具有”、“包含”和其他类似的词语在详细描述或权利要求书中的使用而言,为避免疑惑,这样的术语旨在以类似于术语“包括”作为开放的过渡词的方式解释而不排除任何附加或其他元素。

如上所述,此处所述的各种技术可结合硬件或软件,或在适当时以两者的组合来实现。如在此所使用的,术语“组件”、“系统”等同样指的是计算机相关实体,或者是硬件、硬件和软件的组合、软件或执行中的软件。例如,组件可以是,但不限于是,在处理器上运行的进程、处理器、对象、可执行码、执行的线程、程序和/或计算机。作为说明,运行在计算机上的应用程序和计算机本身都可以是计算机组件。一个或多个组件可以驻留在进程和/或执行的线程中,并且组件可以位于一个计算机内和/或分布在两个或更多计算机之间。

已经关于若干组件之间的交互描述了前述系统。应该理解,这样的系统和组件可以包括根据前述的各种置换和组合的那些组件或指定的子组件、指定的组件或子组件中的某一些、和/或另外的组件。子组件也可以被实现为通信耦合至其他组件而非被包括在父组件(分层)内的组件。另外,应注意到一个或多个组件可被组合成提供聚集功能的单个组件,或被分成若干单独的子组件,且诸如管理层等任何一个或多个中间层可被设置成通信耦合到这样的子组件以便提供集成功能。此处描述的任何组件也可以与在此未具体描述但本领域的技术人员公知的一个或多个其他组件交互。

考虑到以上描述的示例性系统,参考各附图的流程图将可以更好地理解依照所描述的主题实现的方法。尽管为了简洁起见,作为一系列框示出和描述了方法,但是,应该理解,所要求保护的主题不仅限于所描述的框的顺序,一些框可以按与此处所描绘和描述的不同的顺序进行和/或与其他框并发地进行。尽管经由流程图示出了非顺序或分支的流程,但可以理解,可实现达成相同或类似结果的各种其他分支、流程路径和框次序。此外,并非所有的所示出的方框都是实现下面所描述的方法所必需的。

除了此处所描述的各实施例之外,可以理解,可以使用其他相似的实施例或者可对所述实施例作出修改和添加以便执行对应的实施例的相同或等效的功能而不背离这些实施例。此外,多个处理芯片或多个设备可共享此处所描述的一个或多个功能的执行,并且类似地,存储可以跨多个设备实现。因此,本发明不应限于任何单个实施例,而是应该根据所附权利要求书的广度和范围来解释。

去获取专利,查看全文>

相似文献

  • 专利
  • 中文文献
  • 外文文献
获取专利

客服邮箱:kefu@zhangqiaokeyan.com

京公网安备:11010802029741号 ICP备案号:京ICP备15016152号-6 六维联合信息科技 (北京) 有限公司©版权所有
  • 客服微信

  • 服务号