700 likes | 896 Views
第 12 章 Visual Prolog 程序元素. 12.1 项 12.2 常量 12.3 谓词 12.4 子句 12.5 事实 12.6 评估 12.7 程序段 本章小结 本章习题. 12.1 项. 本章介绍 Visual Prolog 的程序元素,内容包括项( Terms )、常量、谓词、子句、事实、运算、程序段等。. 12.1.1 项的基本概念. 项有两种类型:公式 formulas 和表达式 expressions 。 表达式代表数值,比如数字 7 ;公式代表逻辑声明,比如 “ 数字 7 比数字 3 大 ” 。
E N D
第12章 Visual Prolog程序元素 • 12.1 项 • 12.2 常量 • 12.3 谓词 • 12.4 子句 • 12.5 事实 • 12.6 评估 • 12.7 程序段 • 本章小结 • 本章习题 AI程序设计
12.1项 • 本章介绍Visual Prolog的程序元素,内容包括项(Terms)、常量、谓词、子句、事实、运算、程序段等。 AI程序设计
12.1.1项的基本概念 • 项有两种类型:公式formulas和表达式expressions。 • 表达式代表数值,比如数字7;公式代表逻辑声明,比如“数字7比数字3大” 。 • 下面是项的简化定义,其中包括非法的语法结构。例如,! + !的书写形式是不合法的。但是,相信在和语言概念的直觉理解相结合时,使用这样的简化语法表示,在大多数情况下对于类型系统和运算符层次结构的描述更为有利。 AI程序设计
12.1.1项的基本概念 • term: • (term) • unaryOperator term • term binaryOperator term • literal • identifier • qualifiedName • globalName • memberAccess • predicateCall • cut • ellipsis • factvariableAssignment • 文字有通用类型: • literal: • stringLiteral • characterLiteral • integerLiteral • realLiteral • binaryLiteral • cut: • ! AI程序设计
12.1.1项的基本概念 • 谓词调用 • 一个谓词调用形式如下: • predicateCall: • term(term-comma-sep-list-opt) • 首项必须直接声明调用谓词的名字。就是说,首项必须是一个谓词名,一个限定谓词名或一个成员访问。 • 注意,有些谓词有返回值,有些则没有返回值。如果一个谓词有返回值,这个值就必须在上下文中使用,不能被忽略。 AI程序设计
12.1.1项的基本概念 • 事实赋值 • 赋值操作符 := 用于向事实变量factVariable赋予一个新值。项term必须被赋于一个适当类型(即与事实变量或子类型相同的类型)的值。 • factVariableAssignment: • factVariable:=term AI程序设计
12.1.2运算符 • 运算符(Operators)按优先层次进行组织。在规则中,下面各组中的操作符具有相同的优先权,并且上面的操作符比下面的优先级高。就是说,一元加减法要比乘法运算符优先级高,而乘法运算符又比加法运算符高。圆括号可以改变运算优先级。 • unaryOperator: • - + • binaryOperator: • multiplicationOperator • additionOperator • relationOperator • andOperator • orOperator AI程序设计
12.1.2运算符 • 12.1.2.1 算术运算符 • 算术运算符(Arithmetic Operators)用于数字的算术运算。它们是表达式,用表达式作为参数。它们采用根类型作为参数,并返回通用类型的结果。(参见通用类型和根类型)所有的算术操作符都是左结合的(left associative)。 • multiplicationOperator: one of • * /divmod • additionOperator: one of • +- AI程序设计
12.1.2运算符 • 12.1.2.2 关系运算符 • 关系运算符(Relational Operators)是公式,用表达式作参数。它们从本质上是无关联的。 • relationOperator: one of • > < > = <= <> >< = AI程序设计
12.1.2运算符 • 12.1.2.3 逻辑运算符 • 逻辑运算符(Logical Operators)主要包括逻辑“与(and)”、逻辑“或(or)”及逻辑“非(not)” 运算符等。逻辑“与”运算符andOperator和逻辑“或”运算符orOperator是公式,用公式作参数。它们是左结合的。" ,"和 " and "是同义词," ;" 和" or "也是同义词。 andOperator: one of ,and orOperator: one of ;or AI程序设计
12.1.2运算符 • 运算符举例: • 以下的项 • 7 + 3 * 5 * 13 + 4 + 3 = X / 6 ; A < 7, p(X) • 与下面的项含义相同: • ((((7 + ((3 * 5) * 13)) + 4) + 3) = (X / 6)) ; ((A < 7) , p(X)) • 也就是说,项的最外面一层是两个项的“or”,而第一项是一个(=)关系项,第二项是"and"关系项。 AI程序设计
12.1.3类成员访问 • 类实体通过限定类名的方式进行访问: qualifiedName: identifier::identifier • 这样的限定名像普通的名字一样使用,即如果它是一个谓词,它就可以用于一个参数集。 • 有些名字访问不需要限定,参见有关作用域的内容。 AI程序设计
12.1.4对象成员访问 • 每当引用一个对象时,都可以访问该对象的对象成员谓词。 memberAccess: term :identifier • (目前,项term必须是一个变量或一个事实变量) • 标识符identifier必须是项term的类型。 • 在一个实现内部,对象成员谓词不需要引用对象就可以被调用,因为"This"已经被包含在其中了。参见有关作用域的内容。 AI程序设计
12.1.5全局实体的访问 • 存在于Visual Prolog中的仅有的全局实体是类、接口和内部论域、谓词、常量。全局名在任意作用域内都可以直接访问。也可能存在全局名与局域名或输入名重合的情况。在这种情况下,全局实体可以用双冒号‘::’来限定(不带前缀的类名或接口名)。双冒号可以随处使用,但是最重要的用处还是接口名用作形式参数类型说明符的情况。 • globalName: • ::identifier AI程序设计
12.1.6 论域、算符和常量访问 • 论域、算符和常量都像类成员一样被访问。即便它们在一个接口中被声明。 • 这就是说,当它们要被限定的时候,就总是以类或接口名加双冒号来限定。 AI程序设计
12.2常量 • 本节介绍常量(Constant)的有关概念,内容包括常量段、常量定义等。 AI程序设计
12.2.1常量段 • 一个常量段(Constants Section)定义了当前作用域内的常量集。 • constantsSection : • constantsconstantDefinition-dot-term-list-opt AI程序设计
12.2.2常量定义 • 常量定义(Constant Definitions)声明一个命名的常量,包括它的类型和值。 • constantDefinition : • constantName:typeName=constantValue • constantName : • lowerCaseIdentifier • 常量值constantValue是一个表达式,在编译时间内计算。常量名ConstantName应该是一个小写标识符lowerCaseIdentifier。 • 如果一个类型名typeName论域是一个标准论域,那么它和冒号' : '可以被省略,得到以下简写形式: AI程序设计
12.2.2常量定义 • constantDefinition : • constantName=constantValue • 以这样的方式定义的常量可以用于所有的上下文中,在这里可以使用与其同一种类的文字。 • 如果类型名typeName被省略,那么常量论域必须明确地被常量值表达式确定。仅在下列内部论域情况下,typeName才能被省略。 • a)数字(整数或实数)常量。在这种情况下,相应的匿名数字论域被采纳为常量(详细情况参见数字论域) • b)二进制常量。 • c)字符串常量。 • d)字符常量。 AI程序设计
12.3谓词 • 本节介绍谓词(Predicates)的有关概念,内容包括谓词段(Predicates Sections)、构造段(Constructors Sections)、接口谓词(Predicates from Interface)、谓词的元(Arity)等。 AI程序设计
12.3.1 谓词段 • 谓词段声明当前作用域内的对象或类谓词的集合。 • predicatesSection : • class-opt predicates predicateDeclaration-dot-term-list-opt • 关键字class只能在类实现内部使用,这是因为在接口中声明的谓词永远是对象谓词;在类声明中声明的谓词永远是类谓词。 AI程序设计
12.3.1 谓词段 • 谓词声明 • 类声明用于声明作用域中的谓词,在作用域中这些谓词是可见的。当谓词在一个接口定义中被声明时,就是说相应类型的对象必须支持这些谓词。当谓词在类声明中被定义时,就是说该类提供所声明的公用谓词。并且,如果谓词在类的实现中被声明的话,那么该谓词就在局部可用。在所有的情况下,必须存在谓词的相应定义。 • predicateDeclaration : • predicateName:predicateDomain linkName-opt • predicateName:predicateDomainName linkName-opt • linkName : • asstringLiteral • predicateName : • lowerCaseIdentifier • 这里predicateDomainName是在论域段声明的谓词论域名。 AI程序设计
12.3.1 谓词段 • 一个谓词声明,声明了该谓词的名称以及类型、模式、流(参见谓词论域)和可选的一个连接名。 • 只有类谓词可以有连接名。如果没有声明连接名,那么就从谓词名取连接名,取名的方式取决于调用约定。 • 如果调用约定是apicall,那么as子句中所声明的连接名就可以采用任意方式修饰;如果该修饰不是所要的,则用stdcall代替。 AI程序设计
12.3.2 构造段 • 构造段声明了构造器的集合。这些构造器属于所出现的构造段的作用域(参见类声明和类实现)。 • constructorsSection : • constructorsconstructorDeclaration-dot-term-list-opt • 构造段只能出现在构造对象的类的声明和实现当中。 AI程序设计
12.3.2 构造段 • 构造声明 • 构造声明用于声明类的已命名的构造器。 • 实际上,构造器包含两个相关谓词。 • * 一个类函数,返回一个新的被构建的对象; • * 一个对象谓词,在初始化继承对象时使用。 • 一个相关的对象谓词构造器用于执行一个对象的初始化。该谓词只能从该类自身的构造器或是该类的继承类的构造器中调用(即基本的类初始化)。 • constructorDeclaration : • constructorName:predicateDomain • 给构造器声明谓词模式是非法的,构造器总是过程模式的。 AI程序设计
12.3.2 构造段 • 举例 • 考虑下面的类: class test_class : test constructors new : (integer Argument) . endclass test_class • 相关的类级的谓词形式如下(有以下标志): class predicates new : (integer) -> test. • 而相关的对象级的谓词形式如下: predicates new : (integer). AI程序设计
12.3.2 构造段 • 再考虑下面的实现: implement test2_class inherits test_class clauses new() :- test_class::new(7), % invoke the base class constructor on "This" p(test_class::new(8)). % create a new object of the base class and pass it to p(...) ... • 第一次调用test_class::new不返回值,因此这是对构造器的非函数对象的一次调用。就是说,这是基本类构造器"This"的一次调用。 • 第二次调用返回一个值,因此它是对类的构造器的函数调用。就是说,创建了一个新的对象。 AI程序设计
12.3.3 接口谓词 • 一个接口能够通过在predicates from段声明的谓词来支持另一接口的子 • 集。predicates from 段指定接口和所有支持的谓词。这些谓词以名字或者名 • 字和元数来声明。 • 如果一个接口支持另一个接口的子集,那么它就不是与另外那个接口相关的 • 子类型或超类型。 • 关于predicates from段重要的是,所提及的谓词保留它们的原始接口。因 • 此: • * 来自原始接口的任意谓词不会发生支持冲突; • * 它们能够作为来自原始接口的谓词被继承。 • predicatesFromInterface : • predicatesfrominterfaceNamepredicateNameWithArity-comma-sep-list-opt • predicatesFromInterface只能在接口定义中被使用。 AI程序设计
12.3.3 接口谓词 • 举例 • interface aaa • predicates • ppp : (). • qqq : (). • end interface aaa • interface bbb • predicates from aaa • ppp • predicates • rrr : (). • end interface bbb • interface ccc supports aaa, bbb • end interface ccc • 即使aaa和bbb都声明了谓词ppp,但ccc可以不产生任何冲突地支持二者。这是因为ppp在所有情况下都含有aaa,将其作为原始接口。 AI程序设计
12.3.3 接口谓词 • 举例 • interface aaa • predicates • ppp : (). • qqq : (). • endinterface aaa • interface bbb • predicatesfrom aaa • ppp • predicates • rrr : (). • endinterface bbb • class aaa_class : aaa • endclass aaa_class • class bbb_class : bbb • endclass bbb_class • implement aaa_class inherits bbb_class • clauses • qqq(). • endimplement aaa_class aaa_class可以从bbb_class继承ppp,因为ppp在两个类中都含有aaa,并将其作为原始接口。 AI程序设计
12.3.4 变元 • 使用N个参数的谓词被称为N元谓词(N-ary),或者说该谓词有N个变元。所含变元数不同的谓词,即使它们名称相同,通常也是不同的谓词。 • 在大多数情况下,一个谓词的元数在包含该谓词的上下文中是明显的。但是,在某些情况,比如,接口谓词段predicatesFromInterface段和resolve限定中,变元数并不明显。 • 为了区别predicates from 段和resolve限定中不同变元数的谓词,谓词名可以选择采用带有变元数的声明。 AI程序设计
12.3.4 变元 • 下列变元数是可能的: • · Name/N 指一个普通谓词 (即不是一个函数)的名字,变元个数为N; • · Name//N 指一个函数名,变元个数为N; • · Name/N... 指一个带N个变元的普通谓词名,后跟一个省略参数 (即个数可改变的参数) • Name//N... 指一个带N个变元的函数名,后跟一个省略参数。 AI程序设计
12.3.4 变元 • predicateNameWithArity : • predicateNamearity-opt • arity : • /integerLiteral ellipsis-opt • //integerLiteral ellipsis-opt • 在Name/0... 和Name//0... 中,0是可选项,因此它们可以分别写作Name/... 和 Name//...。 • 注意,省略号"…"可以作为最后一个形式参数用于谓词和谓词论域的声明。在这种情况下,就是指所声明的谓词(或谓词论域)的参数个数是可改变的。省略流必须与一个省略参数匹配,因此只能是流模式中的最后一个流。 AI程序设计
12.4 子句 本节介绍子句(Clauses)的有关内容,包括子句段(Clauses Sections)、目标段(Goal Sections)等。 AI程序设计
12.4.1 子句段 • 子句段由子句集组成。子句段包括谓词的实现或事实的初始化值。 • 一个单独的子句段可以含有几个谓词和事实的子句。另一方面,同一谓词或事实(同名并变元数相同)的所有子句必须集中在一个子句段中,并且不涉及其它谓词或事实的子句。 • clausesSection : • clausesclause-dot-term-list-opt • 子句用于定义谓词。单一的谓词由一个子句集定义。每个子句依次执行,直到其中一个子句成功,或没有子句可执行为止。如果没有子句成功,该谓词失败。 • 如果一个子句成功,并且在一个谓词的剩余部分有更多相关子句,那么程序控制将在以后回溯到该谓词的子句,以查找其它的解决方案。 AI程序设计
12.4.1 子句段 • 子句由一个子句头(head)和一个可选的子句体(body)组成。 • clause : • clauseHeadreturnValue-optclauseBody-opt • clauseHead : • lowercaseIdentifier(term-comma-sep-list-opt) • returnValue : • =term • clauseBody : • :-term AI程序设计
12.4.2 目标段 • 目标段是一个程序的入口。当程序开始执行时,首先从目标段开始执行,目标段被执行完后,程序就退出。 • goalSection : • goalterm. • 目标段由一个子句体组成。目标段定义了它自身的作用域,因此所有的调用都应当包含类的限定符。 • 通常,目标必须是过程模式。 AI程序设计
12.5 事实 • 本节介绍事实(Facts)的有关内容,包括事实段(Facts Sections)、事实声明(Fact Declarations)、事实变量(Fact Variables)等。 AI程序设计
12.5.1 事实段 • 一个事实段声明一个由若干事实组成的事实数据库。该事实数据库及事实属于当前作用域。 • 事实数据库可以存在于类级别上,也可以存在于对象级别上。 • 事实段只能在类实现中进行声明。 • factsSection : • class-optfactsfactsSectionName-optfactDeclaration- • dot-term-list-opt • factsSectionName : • -lowerCaseIdentifier AI程序设计
12.5.2 事实声明 • 事实声明用于声明一个事实数据库的事实。事实声明也是一个事实变量或一个事实算符。 • factDeclaration : • factVariableDeclaration • factFunctorDeclaration • factFunctorDeclaration : • factName:(argument-comma-sep-list-opt)factMode-opt • factName : • lowerCaseIdentifier • 一个事实算符声明缺省为nondeterm事实模式。 AI程序设计
12.5.2 事实声明 • 一个事实算符可以通过子句段进行初始化。在这种情况下,子句中的值应当是表达式,这些表达式可以在编译时间内进行求值。 • factMode : one of • determnondetermsingle • 如果模式为single,那么一个事实就有一个值并且只有一个值,而且谓词assert会给原来的值赋新的值。谓词retract不用于单个事实。 • 如果模式为nondeterm,那么这一事实就可以有0个、1个或任意其它个值。如果模式为determ,那么事实可以有0或1个值。如果事实有0个值,那么任何读操作都会失败。 AI程序设计
12.5.3 事实变量 • 一个事实变量与一个一元单个事实算符类似。但是,从语法上讲,它作为可 • 变变量(即以赋值方式)使用。 • factVariableDeclaration : • factVariableName:domaininitialValue-opt • initialValue : • :=constantValue • factVariableName : • lowerCaseIdentifier • 一个常量值constantValue应当是一个项(论域类型的),可以在编译时间求值。 • 只要在一个构造器中将事实变量初始化,那么常量值就可以省略。类事实变量应当总有一个初始的常量值。 AI程序设计
12.5.3 事实变量 • 注意,关键字erroneous可被用来将其值赋给事实变量。下面两行是有效的: • facts • thisWin : vpiDomains::windowHandle := erroneous. • clauses • p() :- thisWin := erroneous. • 用erroneous赋值的基本思想,是为了在某些代码错误地使用了未初始化的事实时,给出一个明确的运行时间错误。 AI程序设计
12.5.4 事实 • 事实只能在类实现中进行声明,并且以后它们只能从这个实现被引用。因此事实的作用域就是它们被声明的这个实现。但是对象事实的生命期是它所属的对象的生命期。同样地,类事实的生命期是从程序开始到程序结束。 • 举例 • 下面的类声明了一个对象事实objectFact和一个类事实classFact: • implement aaa_class • facts • objectFact : (integer Value) determ. • classfacts • classFact : (integer Value) determ. • ... • end implement aaa_class AI程序设计
12.6 评估 • 评估(Evaluation)又称为求值运算。Visual Prolog通过执行目标来实现。 • 目标是一个项。本节叙述项和子句的执行或计算是怎样进行的,包括回溯(Backtracking)、谓词调用、合一(unification)、引用论域、匹配、嵌套的函数调用、变量与常量、算术表达式、事实断言与撤消等。 AI程序设计
12.6 评估 • 12.6.1 回溯 • 12.6.2 谓词调用 • 12.6.3 合一 • 12.6.4 引用论域 • 12.6.5 匹配 • 12.6.6 嵌套的函数调用 • 12.6.7 变量与常量 • 12.6.8 算术表达式 • 12.6.9 事实断言与撤消 • 12.6.10 失败谓词和 • 成功谓词 • 12.6.11 逻辑与 • 12.6.12 逻辑或 • 12.6.13 逻辑非 • 12.6.14 截断 • 12.6.15 谓词finally/2 AI程序设计
12.6.1 回溯 • 一个Prolog程序的评估或运算是搜索求解的过程。搜索求解的每一步或者成功或者失败。在程序执行的特定点上,有可能不止有一种解决方案。当遇到这样的选择点时,就建立所谓的回溯点。一个回溯点是程序状态的一个记录,即添加一个指针到未执行的选择点。如果它证明了初始的选择不能提供解决方案(即失败),那么程序将回溯到记录过的回溯点,从而恢复程序状态和追踪另一个选择。在下面的部分还将对该机制进行详细描述和解释。 AI程序设计
12.6.2 谓词调用 • 通过使用参数到一个谓词实现该谓词的调用。该谓词必须有一个流模式,以匹配参数的自由或绑定状态。每个谓词由一个子句集合(或在外部用某种其它语言)定义。 • 当谓词被谓词调用引用时,每个子句依次执行直到它们成功,或直到没有子句可执行为止。如果没有子句成功,那么该谓词失败。 • 如果一个子句成功并且还剩有其他的有关子句,那么程序控制可以在以后回溯到剩余的子句,以搜索其它的解。 AI程序设计
12.6.2 谓词调用 • 举例 • clauses • ppp() :- qqq(X), • write(X), fail. • qqq(1). • qqq(2). • qqq(3). 当ppp被调用时,它依次调用qqq。当qqq被调用,它首先建立一个指向第二个子句的回溯点。然后执行第一个子句。因此ppp中的自由变量X与数字1匹配,从而X被绑定为1。 在ppp执行时,X(即1)被写出后,由fail援引回溯点。从而程序控制被设置到qqq中的第二个子句,并且程序状态被设置回qqq首次进入的状态,即ppp 的X不再被绑定。 在qqq中的第二个子句实际执行之前,第三个子句的回溯点已经建立好了。 AI程序设计
12.6.3 合一 • 当一谓词被调用时,来自调用的参数与每个子句的子句头的项合一。 • 合一是绑定变量的过程,在这一过程中,两项通过尽可能少的绑定达到相等(即为进一步绑定留下尽可能多的开放空间)。 • 变量可以绑定为各种项,包括变量或含有变量的项。 • 合一有时可能有时不可能,也就是说它可能成功也可能失败。 • 变量和与其合一的项是有类型的,一个变量只能被绑定到与它类型相同的项或子类型上。当两个变量互相绑定时,它们就必须是完全相同的类型。 • 如上所述,合一发生在一个谓词调用和子句头之间,也发生在比较两项是否相等之时。 AI程序设计