Fuxi程序设计语言
§1. 技术要点
Fuxi语言的设计哲学,并不是刻意地去发明一项新的语言技术,而是将过去散落在各种不同语言中的优秀思想,经过精心地组合,并以一种通俗流行的形式展现出来。
Fuxi语言采用一种为广大程序员所熟知的、广泛流行的语言构件,综合面向对象的、函数型的、逻辑型的程序设计模式中的优秀思想,结合计算技术的新发展(特别是互联网技术),旨在增强语言的建模能力、缩小程序模型与现实世界之间的“语义鸿沟”,让程序员能够以一种轻松自然的方式,进行程序设计。
程序设计语言是一项综合的软件技术,通常包括语言定义(Specification)、语言实现(Implementation)和支持环境(Supporting
Environment)等部分。这里,我们列举了Fuxi语言的4个最重要的技术侧面,它们体现了Fuxi技术的基本概貌,也是Fuxi语言的重要的技术创新点。
-
一种将面向对象、函数型及逻辑型语言结合的文法系统
-
正交的对象风格化
-
Fuxi语言的跨平台实现方案
-
一种结合对象管理和可回溯规约的抽象机模型
§2. 为什么要开发Fuxi语言?
著名的计算机科学家E.W. Dijkstra指出“程序设计的艺术就是管理复杂性的艺术”,同时他又指出“我们必须用这样的方式来组织计算,使得用有限的能力足于保障计算能获得我们所需要的效果”。那么究竟用什么样的方式来组织计算,才能在有限的能力范围内获得需要的效果呢?在上个世纪的60~70年代,这个方式就是结构化程序设计,当时以PASCAL、C为代表的语言正体现了这种结构化的程序设计思想。进入80年代后,随着计算复杂性的增大,结构化程序设计已经不能满足需要了,于是面向对象的技术取代了结构化程序设计。进入90年后,面向对象的技术发展到了顶峰,面向对象的语言以Smalltalk、C++和JAVA为代表。 进入90年代后,网络技术得到了空前的发展。而进入21世纪后,网络计算主导着整个计算机界,尤其是新一代互联网及网格计算的出现,传统的面向对象技术已经不能驾御这种由网络计算所带来的新的计算复杂性了。
正如K. Louden教授指出的那样,“只要有新的计算技术的出现,就有新的程序设计语言和新的思想产生的空间。”
Fuxi语言正是在这种背景下提出的。Fuxi试图通过将不同程序设计模式(Paradigms)中的优秀思想结合起来,形成一个集成的、一致的新型程序模式。利用面向对象技术的良好的建模能力、代码的可复用性,说明性语言的强大的表述能力、引用透明性、执行的次序无关性和可并行性,让程序设计变成一件令人愉快的事情。
我们设计Fuxi语言不是去证明一种观点,而是去解决一些问题。Fuxi语言来自于实践,服务于应用。Fuxi语言是我们在努力地解决复杂系统建模问题的过程中提出的,在Fuxi语言诞生的第一天起,Fuxi语言就有了应用。因此,Fuxi语言也是一种面向问题的程序设计语言。我们正是把人工智能中的某些方法,结合面向对象和网络技术,通过Fuxi语言,在一些需要智能才能解决的问题(例如管理问题、工业测试问题等)中综合地加于应用。
§3. Fuxi的文法系统
Fuxi语言(Fuxi Programming
Language)是一种通用的、高级的、面向对象的函数逻辑型的程序设计语言。它采用C++风格的面向对象的文法形式来体现函数型、逻辑型的程序设计思想,从而综合了这些语言模式的优点,缩小程序模型与现实世界之间的“语义鸿沟”,提高语言的建模能力,降低编程的难度,最终提高软件的产出力。
Fuxi语言的特点具体表现为以下几个方面:
§3.1 语言构件通俗化、流行化,简单易学
在Fuxi语言的设计过程中,我们始终把简单易学作为一个重要指标。因此,在选择语言构件时,总是尽可能地保持同主流语言的一致性,充分考虑程序员对主流语言的习惯性。Fuxi语言的数据定义和C++、JAVA、C#大体相同,但Fuxi的方法区分函数、子句和触发器等。Fuxi采用模式匹配(Pattern
Matching)的方式以一致的形式定义方法。例如:
// 这是一个Fuxi控制台应用程序 import fuxi.* public active class Fibonacci :
Application { int n =
System.Console.Readln().ToInteger()
// Fibonacci函数定义 public Fib(0) = 1 public Fib(1) = 1 public Fib(int n) = Fib(n – 1) +
Fib(n – 2) // 内存分配出错 OnError( ERROR_MEMORY_ALLOCATION )
-> System.Console.Println( "内存溢出" )
public Activate( ) = { System.Console.Print( "请输入:" ) System.Console.Println( "Fib("
+ n + ")=" + Fib(n) ) } }
该程序的计算结果为:
请输入:5 Fib(5)=8
这是一个典型的Fuxi控制台应用程序,它计算Fibonacci数。从这个例子中我们可以看出:
-
Fuxi的文法和C++、JAVA或C# 极其相近;
-
Fuxi采用模式匹配的方式定义方法,如Fib函数,包含三个模式Fib(0)、Fib(1)和Fib(n);
-
Fuxi区分函数、子句和触发器,函数的模式和定义体之间采用‘=’连接,而子句采用‘<-’连接,触发器采用‘->’连接,非常直观易懂;
-
Fuxi支持惰性计算,即表达式只有在用到时才计算值。字段n在对象建立时并没有被计算,而只是在被引用时才进行计算。
§3.2
模式扩展与覆盖技术为代码复用提供一个精细方案
在C++、JAVA等语言中,方法的继承与覆盖是对整个方法进行的,而Fuxi语言可以在模式级进行,从而进一步地提高了代码的复用率。例如,我们想在派生类中,对Fib函数进行改造,增加一个Fib(-1)模式,同时修改Fib(0)模式,程序可以写成:
public class NewFibonacci :
Fibonacci { Fib(-1) = 0 // 扩展Fib(-1) Fib(0) = 0 // 覆盖Fib(0) }
§3.3
对象的脚本化定义机制,提高程序的说明性
类中定义的字段如果没有初始化,同时构造函数也没有对其进行初始化,则该字段为自由字段(Free
Field)。Fuxi中公开的自由字段称为槽(Slot)。这样,一个带槽的类就是一个框架。当用这样的带槽类定义对象时,我们可以在对象后附着一个脚本一样的程序段,来填写槽值(Slot
Value)。这种对象的定义机制称为对象的脚本化定义(Scripted
Definition of
Objects)。脚本化定义非常适合描述资源,同时它也进一步地提高了Fuxi语言的说明性。看例子:
class Button { public Button( String title ) = {…} public POINT at // at 槽 public SIZE size // size 槽 … } class Field { public Field( String text ) = {…} public POINT at // at 槽 public SIZE size // size 槽 } … Field fldName( "海创达" ) { at : 100, 100 // 填写at的槽值 size: 200, 30 // 填写size的槽值 } Button btnExit( "退出" ) { at : 200, 200 size: 80, 40 }
§3.4 受卫字段(Guarded
Field),提高程序安全性
我们可以为Fuxi的字段提供一组卫兵(Guards),卫兵是函数或子句。用{}将卫兵扩起来,附着在字段的后面。Fuxi字段的卫兵可以是:
-
When() = <条件表达式>
-
Valid() = <条件表达式>
-
Before() -> <动作表达式>
-
After() -> <动作表达式>
Fuxi对字段的修改过程为:
-
如果没有定义When()函数, 则转步骤3;
-
计算When()函数,如果值为false, 则转步骤10;
-
如果没有定义Before()触发器,则转步骤5;
-
执行触发器Before();
-
保存字段的原值;
-
修改字段的值;
-
如果没有定义Valid()函数,则转步骤11;
-
计算函数Valid(),如果值为true,则转步骤11;
-
恢复字段的原值;
-
修改失败,返回false;
-
如果没有定义After()触发器,则转步骤13;
-
执行触发器After();
-
修改成功,返回true。
我们来看一个程序段:
class Voucher { protected Date date { After() -> { year.Invalidate()
month.Invalidate() day.Invalidate() } } public virtual int year =
date.GetYear() { When() = year > 2003 Valid() = year >1980 && year <
2050 After() = date := Date( year,
month, day ) } public virtual int month =
date.GetMonth() { Valid() = month >= 1 && month <=
12 After() -> date := Date( year,
month, day ) } public virtual int day = date.GetDay() { Valid() = day >= 1 && day <= 31
&& Date(year, month, day).GetDay() ==
day After() ->date := Date( year,
month, day ) } }
§4. 正交的对象风格化
正交的对象风格化(Orthogonal Stylization of
Objects)指的是对象风格和对象类型正交。对象风格指对象在执行过程中表现的姿态,例如,是否拥有自己独立的线程、是否具有持续性、是否可以在网上移动等;而对象类型指对象的结构和行为,对象类型通常是类。我们可以把对象的风格想象成产品的颜色,产品的设计师通常关注产品结构本身的设计,而忽略对颜色的考虑。然而,当产品成型后,工人可以为产品着上各种不同的颜色。
图1. 实例的三维空间
例如,我们定义了类A后,可以定义几种不同风格的对象: class A { … } active A a_act // 主动式对象a_act mobile A a_mob // 可移动对象a_mob persistent A a_per // 持续性对象a_per remote A a_rem // 远程对象a_rem
这四个对象都具有相同的类型,具有相同的调用接口。在程序设计过程中,程序员可以完全不必对这三个姿态不同的对象进行特殊的考虑。因为,对象风格只是在执行时才表现出来。Fuxi语言目前支持的风格有active,
mobile, persistent,
remote,同时Fuxi也提供对用户自定义风格的接口(目前尚处实验阶段)。
正交的对象风格化是Fuxi语言提出的一个极其重要的概念,是面向对象技术的一个新发展。我们提出的实例空间的三维模型,开拓了程序设计的视野,提高了语言的说明性和问题的描述能力。虽然,有关风格的技术实现早已是成熟的技术,但是象Fuxi这样系统地提出风格化概念的语言尚属罕见。
Fuxi在语言级对风格提供支持,可以让程序员只关注类结构本身的设计,关注问题的本身,而忽略对同问题方案正交的某些技术侧面的考虑。
传统的面向对象其实是在上述实例空间的类平面上的演绎过程。我们来看一个例子,
class A { int attr1; …… } class B : Thread { int attr1; …… } class C : A, Thread { …… } A a; B b;
我们要定义两个具有相同结构的对象,一个是主动的,而另一个是被动的,我们必须定义新的类(B,
C),要么重写一个类B,要么采用多重继承(类C)。很显然,A和B是两个完全不同的类型,不能分享它们的共同属性;而C虽然能共享A的属性,但采用了颇受争议的多重继承,同时A、C也不具有同态的结构。
正交的风格能很好地解决这个问题。利用风格为对象着色(Coloring),对象空间里的这些“彩色对象”既能维持原有的性状,又展现了自己的风格。
我们对风格进行扼要说明。
§4.1主动式对象
Fuxi中带有active风格的对象,称为主动式对象(Active
Object),其它非主动式对象称为被动式对象(Passive
Object)。每个主动式对象都具有独立的线程、独立的消息队列、独立的执行堆栈。出于实现上的考虑,Fuxi规定,每个被动式对象必须包含于某个主动式对象。主动式对象内部的方法调用(Method
Invocation),就是普通的调用(Call),而两个主动式对象之间的方法调用,则通过消息传递(Message
Passing)来进行。
在程序执行中,Fuxi抽象机在创建一个对象时,如果发现它是一个主动式对象时,在按正常方式创建该对象时,同时为其分配一个Actor一样的执行线程,在进行完数据初始化后,进入消息循环。
§4.2 持续性对象
所谓持续性对象(Persistent
Object)指那些在程序执行完毕时,可以自动地保存到磁盘中(一般为对象库),当程序再次执行时,可以从磁盘中自动地装载的对象。Fuxi中通过persistent风格来标注持续性对象。为了数据的完整性,Fuxi规定:如果一个对象被标注为持续性对象,则该对象的包含的所有的引用对象均为持续性对象。
程序执行中,Fuxi抽象机在创建对象时,如果发现所创建对象是一个持续性对象,则根据程序的执行签名(程序名、站点IP、用户名等)判断该程序是否是初次执行,如果是初次执行,则在对象库中为该对象创建一个持续性影像,同时对对象进行初始化;如果不是初次执行,则根据这个签名从数据库中装载该对象。注意:系统不对再次执行的持续性对象进行初始化。程序执行完毕前,系统将所有持续性对象的影像flush到磁盘中,供下次执行时装载。
§4.3 远程对象
当前执行空间以外的对象,均为远程对象。它可以是网络上另一台计算机上的对象,也可以是同一台计算机上的另一进程中的对象。Fuxi中远程对象是通过remote风格来标注的。
程序执行中,Fuxi抽象机在创建对象时,如果发现所创建的对象为远程对象,则创建一个该对象的代理(Proxy),并通过该代理和Fuxi平台的远对象激活(Remote
Object
Invocation)机制,建立远对象的连接。数据访问通过代理来完成。
§4.4 可移动对象
Fuxi是一个面向网络的程序设计语言。Fuxi的可移动对象(Mobile
Object)指那些可以从一个执行空间中迁移到另一个执行空间中去的对象。对象为什么要迁移呢?
第一、远程对象的请求。当远程对象向一个可移动对象发出了调用请求时,如果该对象又满足迁移的条件(如当前空闲,没有其它的执行任务),则从本地迁移到请求站点上去。
第二、寻找本地不具有的资源。当某个方法在执行中需要某种本地没有的资源时,系统根据该资源的URL来定位资源的站点,同时把这个可移动的对象迁移到那个站点上去。
第三、因设备的移动,需要把为该移动设备提供服务的某个可移动对象从一个网段迁移到另一个网段上去。 出于实现上的考虑,目前规定:可移动对象也必定是主动式对象。当Fuxi抽象机创建对象时,如果发现所创建的对象为可移动对象,则为其创建一个可移动的Actor(简称m-Actor,或MA)和一个连接该Actor的代理(Proxy)。对可移动对象的访问,都是通过该代理向m-Actor发送消息进行的。代理中包含m-Actor的当前位置,确保可移动对象不会在网上迷失。
§5. Fuxi的跨平台实现方案
Fuxi是一个面向网络计算的程序设计语言。作为一个网络编程语言,Fuxi必须解决能够在不同体系结构的机器上执行的问题,即跨平台问题。Fuxi的跨平台方案是这样的:
-
Fuxi编译器将Fuxi源代码编译成一种称为Fuxi对象图的计算图;
-
Fuxi对象图的数据表示采用一种与平台无关的、符合网络标准的表示方法;
-
通过运行于各平台上的Fuxi抽象机来对Fuxi对象图进行图规约计算,获得计算结果。
§5.1 Fuxi对象图的基本结构
Fuxi对象图(Fuxi Object Graph,FOG)是一种框架化的计算图(Computational
Graph)。它包括关联部分、结构部分、数据部分和节点部分等。
-
关联部分(Dependencies):记录本FOG对其它FOG的关联信息,Fuxi抽象机正是根据这部分信息,连接其它FOG模块的;
-
结构部分(Structures):结构是指表示类、字段、方法等数据结构;
-
数据部分(Data):主要记录程序中出现的各种常数;
-
节点部分(Nodes):节点指Fuxi对象图上的计算节点,为能进行高效的存储和变换,Fuxi中所有计算节点都固定为一个整数字长度,即4个字节。其结构如图所示:
Fig2. 计算节点
其中opcode是该节点的操作码,它定义节点的操作语义。opcode为一个字节长度,共255个。op-ext是操作扩展码,对opcode进行补充,不同的opcode有不同的op-ext;通常,op-ext指示该节点的目标类型。data是和节点关联的数据,其含义由opcode确定。
Fuxi对象图的技术特点:
-
区分静态的结构和动态的节点。从实现的角度来看,Fuxi的对象创建过程是结构驱动的(structure-driven),而不是过程驱动的(procedure-driven),如C++等。
-
节点长度固定,正好为一个机器字长度(大多数情况)。这种安排,非常有利于节点的复制,计算图的变换,以及对象的移动。
§5.2 表达式的图表示
我们先来看一个表达式的例子:
x + y * z
在Fuxi对象图中,该表达式表示成:
(x)(y)(z)(*)(+)
我们用括号()表示一个计算节点,括号中的符号是该节点的标注;这是一种典型的后缀式表达,其特点是一次扫描,便可获得计算结果。但是,它不支持惰性计算(Lazy
Evaluation)。Fuxi是一个惰性语言,支持惰性计算。Fuxi
FOG采用了一种称为子图标注(subgraph
tagging)的技术来解决这个问题。我们先看一个例子,
f( x + y * z, k )
其FOG表示为:
(call, f, 2)(sub, 5)(x)(y)(z)(*)(+)(k)
其中(sub,
5)是一个子图标注节点,他表示其后5个节点为一个参数子图。(call, f,
2)表示对对函数f的调用,其参数个数为2。这样,Fuxi的方法调用成为前缀式表示。当抽象机规约到节点(call,
f, 2)时,参数并没有计算(它们在后面)。抽象机根据节点(call, f,
2)指示的参数个数,将其后的两个参数子图的引用传递给方法f。
§5.3 FOG的特点和技术优势
Fuxi的FOG和JAVA的BYTE-CODE的本质区别就在于,FOG是一个经特殊处理的图,对其的计算实质上是根据规约条件对图进行的变换。而BYTE-CODE是一种抽象的机器指令,抽象机对其进行逐条解释执行。
FOG一个极其重要的特点是:我们可以对FOG进行部分计算(Partial
Evaluation);对FOG中与本地环境关联的节点进行规约,获得一个和本地环境无关的新FOG,把它传递给网上的另一站点,在新站点上再对其进行新的规约计算,直到获得最终结果为止。
FOG的这一特性,使得FOG非常适合网络计算(Network
Computing)和移动计算(Mobile
Computing),尤其是新一代互联网的网格计算技术(Grid
Computing)。
§6. Fuxi的抽象机模型
Fuxi抽象机(Fuxi Abstract Machine,简称FXAM)是Fuxi平台的核心,是一个结合对象管理的、可回溯的抽象机模型。
Fuxi抽象机包括Fuxi的对象接口fuxi.Object、类装载器(Class
Loader)、对象管理器(Object
Manager)、执行单元(Execution Unit)等部分构成。
Fuxi语言中的所有对象都是从一个称为fuxi.Object的对象上派生出来的,fuxi.Object是构成Fuxi语言对象体系的基石。fuxi.Object也是Fuxi语言和其它语言系统之间相互调用的接口。Fuxi语言在设计之初,也是想为其它的软件系统提供一种嵌入式的智能环境。
从功能上看,fuxi.Object类似于COM,都试图去解决不同程序之间的相互引用问题。但COM是对象的过程型实现,而fuxi.Object是对象的说明型实现。由于Fuxi语言是说明型语言,fuxi.Object必然要体现出函数型和逻辑型语言的要求。具体地说,要求fuxi.Object的方法具有可回溯性,也就是说要求fuxi.Object方法在引用失败后,能够无副作用的返回。此外,fuxi.Object还体现了风格化的对象定义和RTTI要求。
在fuxi.Object中,我们把方法分为三种类型:计算(Evaluation)、查询(Query)和触发(Trigger)。Fuxi语言是函数型语言,每个函数都有类型,对函数的计算必须返回一个结果,这时Fuxi对象就是一个计算器;Fuxi语言也是逻辑型语言,当调用方提出一个查询请求时,将激活一个反向推理过程,这时Fuxi对象就成了一个推理机和规则库;当一个外部或内部事件发生后,可能会触发一组动作,这时Fuxi对象又成为一个产生式规则的执行者(Actor)。
fuxi.Object是在Fuxi语言的嵌入式实现过程中提出的,它也可以一般性地理解为一种agent(智能体),可以在其它面向agent的程序设计中加于应用。在Managers?平台上,Manager也可以理解为一种具有对象管理能力的agent。 |