第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 1
第 12章 Visual Prolog程序元素
12.1 项
12.2 常量
12.3 谓词
12.4 子句
12.5 事实
12.6 评估
12.7 程序段
本章小结
本章习题
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 2
12.1 项
本章介绍 Visual Prolog的程序元素,内
容包括项( Terms)、常量、谓词、子句、
事实、运算、程序段等。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 3
12.1.1 项的基本概念
项有两种类型:公式 formulas和表达式 expressions。
表达式代表数值,比如数字 7;公式代表逻辑声明,比如
,数字 7比数字 3大, 。
下面是项的简化定义,其中包括非法的语法结构。例
如,! + !的书写形式是不合法的。但是,相信在和语言概
念的直觉理解相结合时,使用这样的简化语法表示,在大多
数情况下对于类型系统和运算符层次结构的描述更为有利。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 4
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,
!
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 5
谓词调用
一个谓词调用形式如下,
predicateCall,
term ( term-comma-sep-list-opt )
首项必须直接声明调用谓词的名字。就是说,首项必须
是一个谓词名,一个限定谓词名或一个成员访问。
注意, 有些谓词有返回值, 有些则没有返回值 。 如果一个
谓词有返回值, 这个值就必须在上下文中使用, 不能被忽
略 。
12.1.1 项的基本概念
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 6
事实赋值
赋值操作符,= 用于向事实变量 factVariable赋予一个
新值 。 项 term必须被赋于一个适当类型 ( 即与事实变量或子
类型相同的类型 ) 的值 。
factVariableAssignment,
factVariable,= term
12.1.1 项的基本概念
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 7
12.1.2 运算符
运算符( Operators)按优先层次进行组织。在规则中,下面各组中
的操作符具有相同的优先权,并且上面的操作符比下面的优先级高。就
是说,一元加减法要比乘法运算符优先级高,而乘法运算符又比加法运
算符高。圆括号可以改变运算优先级。
unaryOperator,
- +
binaryOperator,
multiplicationOperator
additionOperator
relationOperator
andOperator
orOperator
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 8
12.1.2 运算符
12.1.2.1 算术运算符
算术运算符 ( Arithmetic Operators) 用于数字的算术运算 。 它们是
表达式, 用表达式作为参数 。 它们采用根类型作为参数, 并返回通用类
型的结果 。 ( 参见通用类型和根类型 ) 所有的算术操作符都是左结合的
( left associative) 。
multiplicationOperator,one of
* / div mod
additionOperator,one of
+ -
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 9
12.1.2 运算符
12.1.2.2 关系运算符
关系运算符 ( Relational Operators) 是公式, 用表达式作
参数 。 它们从本质上是无关联的 。
relationOperator,one of
> < > = <= <> >< =
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 10
12.1.2 运算符
12.1.2.3 逻辑运算符
逻辑运算符 ( Logical Operators) 主要包括逻辑, 与 ( and),, 逻辑
,或 ( or), 及逻辑, 非 ( not), 运算符等 。 逻辑, 与, 运算符
andOperator和逻辑, 或, 运算符 orOperator是公式, 用公式作参数 。
它们是左结合的 。 ","和 " and "是同义词, " ; " 和 " or "也是同义词 。
andOperator,one of
,and
orOperator,one of; or
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 11
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"关系项。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 12
12.1.3 类成员访问
类实体通过限定类名的方式进行访问,
qualifiedName,
identifier,,identifier
这样的限定名像普通的名字一样使用,即如果它是一个谓
词,它就可以用于一个参数集。
有些名字访问不需要限定,参见有关作用域的内容。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 13
12.1.4 对象成员访问
每当引用一个对象时, 都可以访问该对象的对象成员谓词 。
memberAccess,
term, identifier
(目前, 项 term必须是一个变量或一个事实变量 )
标识符 identifier必须是项 term的类型 。
在一个实现内部,对象成员谓词不需要引用对象就可以
被调用,因为 "This"已经被包含在其中了。参见有关作用域
的内容。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 14
12.1.5 全局实体的访问
存在于 Visual Prolog中的仅有的全局实体是类、接口和
内部论域、谓词、常量。全局名在任意作用域内都可以直接
访问。也可能存在全局名与局域名或输入名重合的情况。在
这种情况下,全局实体可以用双冒号‘,:’来限定(不带前缀
的类名或接口名)。双冒号可以随处使用,但是最重要的用
处还是接口名用作形式参数类型说明符的情况。
globalName,
,,identifier
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 15
12.1.6 论域、算符和常量访问
论域、算符和常量都像类成员一样被访问。即
便它们在一个接口中被声明。
这就是说,当它们要被限定的时候,就总是
以类或接口名加双冒号来限定。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 16
本节介绍常量 ( Constant) 的有关概念,
内容包括常量段, 常量定义等 。
12.2 常量
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 17
12.2.1 常量段
一个常量段( Constants Section)定义了当前作
用域内的常量集。
constantsSection,
constants constantDefinition-dot-term-list-opt
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 18
12.2.2 常量定义
常量定义( Constant Definitions)声明一个命名的常量,包括它的
类型和值。
constantDefinition,
constantName, typeName = constantValue
constantName,
lowerCaseIdentifier
常量值 constantValue是一个表达式, 在编译时间内计算 。 常量名
ConstantName应该是一个小写标识符 lowerCaseIdentifier。
如果一个类型名 typeName论域是一个标准论域, 那么它和冒号 ', '可
以被省略, 得到以下简写形式,
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 19
12.2.2 常量定义
constantDefinition,
constantName = constantValue
以这样的方式定义的常量可以用于所有的上下文中, 在这里可以使用
与其同一种类的文字 。
如果类型名 typeName被省略, 那么常量论域必须明确地被常量值表
达式确定 。 仅在下列内部论域情况下, typeName才能被省略 。
a) 数字 ( 整数或实数 ) 常量 。 在这种情况下, 相应的匿名数字论域被
采纳为常量 ( 详细情况参见数字论域 )
b) 二进制常量 。
c) 字符串常量 。
d) 字符常量 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 20
12.3 谓词
本节介绍谓词( Predicates)的有关概念,
内容包括谓词段( Predicates Sections)、构造
段( Constructors Sections)、接口谓词
( Predicates from Interface)、谓词的元
( Arity)等。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 21
12.3.1 谓词段
谓词段声明当前作用域内的对象或类谓词的集合。
predicatesSection,
class-opt predicates predicateDeclaration-dot-term-list-opt
关键字 class只能在类实现内部使用,这是因为在接口
中声明的谓词永远是对象谓词;在类声明中声明的谓词永
远是类谓词。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 22
12.3.1 谓词段
谓词声明
类声明用于声明作用域中的谓词, 在作用域中这些谓词是可见的 。 当谓词
在一个接口定义中被声明时, 就是说相应类型的对象必须支持这些谓词 。 当谓
词在类声明中被定义时, 就是说该类提供所声明的公用谓词 。 并且, 如果谓词
在类的实现中被声明的话, 那么该谓词就在局部可用 。 在所有的情况下, 必须
存在谓词的相应定义 。
predicateDeclaration,
predicateName, predicateDomain linkName-opt
predicateName, predicateDomainName linkName-opt
linkName,
as stringLiteral
predicateName,
lowerCaseIdentifier
这里 predicateDomainName是在论域段声明的谓词论域名 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 23
12.3.1 谓词段
一个谓词声明, 声明了该谓词的名称以及类型, 模式,
流 ( 参见谓词论域 ) 和可选的一个连接名 。
只有类谓词可以有连接名 。 如果没有声明连接名, 那么就
从谓词名取连接名, 取名的方式取决于调用约定 。
如果调用约定是 apicall,那么 as子句中所声明的连接名就
可以采用任意方式修饰;如果该修饰不是所要的, 则用
stdcall代替 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 24
12.3.2 构造段
构造段声明了构造器的集合。这些构造器属于所出现的构
造段的作用域(参见类声明和类实现)。
constructorsSection,
constructors constructorDeclaration-dot-term-list-opt
构造段只能出现在构造对象的类的声明和实现当中。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 25
12.3.2 构造段
构造声明
构造声明用于声明类的已命名的构造器 。
实际上, 构造器包含两个相关谓词 。
* 一个类函数,返回一个新的被构建的对象;
* 一个对象谓词, 在初始化继承对象时使用 。
一个相关的对象谓词构造器用于执行一个对象的初始化 。 该谓词只能
从该类自身的构造器或是该类的继承类的构造器中调用 ( 即基本的类初
始化 ) 。
constructorDeclaration,
constructorName, predicateDomain
给构造器声明谓词模式是非法的,构造器总是过程模式的 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 26
12.3.2 构造段
举例
考虑下面的类,
class test_class, test
constructors
new, (integer Argument),
end class test_class
相关的类级的谓词形式如下 ( 有以下标志 ),
class predicates
new, (integer) -> test,
而相关的对象级的谓词形式如下,
predicates
new, (integer),
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 27
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"的一次调用 。
第二次调用返回一个值, 因此它是对类的构造器的函数调用 。 就是说, 创建了一
个新的对象 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 28
12.3.3 接口谓词
一个接口能够通过在 predicates from段声明的谓词来支持另一接口的子
集。 predicates from 段指定接口和所有支持的谓词。这些谓词以名字或者名
字和元数来声明。
如果一个接口支持另一个接口的子集,那么它就不是与另外那个接口相关的
子类型或超类型。
关于 predicates from段重要的是,所提及的谓词保留它们的原始接口。因
此,
* 来自原始接口的任意谓词不会发生支持冲突;
* 它们能够作为来自原始接口的谓词被继承。
predicatesFromInterface,
predicates from interfaceName predicateNameWithArity-
comma-sep-list-opt
predicatesFromInterface只能在接口定义中被使用。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 29
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,将其作为原始接口。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 30
12.3.3 接口谓词
举例
interface aaa
predicates
ppp, (),
qqq, (),
end interface aaa
interface bbb
predicates from aaa
ppp
predicates
rrr, (),
end interface bbb
class aaa_class, aaa
end class aaa_class
class bbb_class, bbb
end class bbb_class
implement aaa_class inherits bbb_class
clauses
qqq(),
end implement aaa_class
aaa_class 可 以 从
bbb_class继承 ppp,因为
ppp在两个类中都含有 aaa,
并将其作为原始接口 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 31
12.3.4 变元
使用 N个参数的谓词被称为 N元谓词( N-ary),或者说该谓词有 N个
变元。所含变元数不同的谓词,即使它们名称相同,通常也是不同的谓
词。
在大多数情况下,一个谓词的元数在包含该谓词的上下文中是明显的。
但是,在某些情况,比如,接口谓词段 predicatesFromInterface段和
resolve限定中,变元数并不明显。
为了区别 predicates from 段和 resolve限定中不同变元数的谓词,
谓词名可以选择采用带有变元数的声明。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 32
12.3.4 变元
下列变元数是可能的,
· Name/N 指一个普通谓词 (即不是一个函数 )的名字,变元个数为
N;
· Name//N 指一个函数名, 变元个数为 N;
· Name/N..,指一个带 N个变元的普通谓词名, 后跟一个省略参数
(即个数可改变的参数 )
Name//N..,指一个带 N个变元的函数名, 后跟一个省略参数 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 33
12.3.4 变元
predicateNameWithArity,
predicateName arity-opt
arity,
/ integerLiteral ellipsis-opt
// integerLiteral ellipsis-opt
在 Name/0..,和 Name//0..,中, 0是可选项, 因此它们可以分别写作
Name/..,和 Name//...。
注意, 省略号 "…"可以作为最后一个形式参数用于谓词和谓词论域的声
明 。 在这种情况下, 就是指所声明的谓词 ( 或谓词论域 ) 的参数个数是
可改变的 。 省略流必须与一个省略参数匹配, 因此只能是流模式中的最
后一个流 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 34
12.4 子句
本节介绍子句( Clauses)的有关内容,
包括子句段( Clauses Sections)、目标
段( Goal Sections)等。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 35
12.4.1 子句段
子句段由子句集组成。子句段包括谓词的实现或事实的初始化值。
一个单独的子句段可以含有几个谓词和事实的子句。另一方面,同一
谓词或事实(同名并变元数相同)的所有子句必须集中在一个子句段中,
并且不涉及其它谓词或事实的子句。
clausesSection,
clauses clause-dot-term-list-opt
子句用于定义谓词。单一的谓词由一个子句集定义。每个子句依次执
行,直到其中一个子句成功,或没有子句可执行为止。如果没有子句成
功,该谓词失败。
如果一个子句成功,并且在一个谓词的剩余部分有更多相关子句,那
么程序控制将在以后回溯到该谓词的子句,以查找其它的解决方案。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 36
12.4.1 子句段
子句由一个子句头( head)和一个可选的子句体( body)组成。
clause,
clauseHead returnValue-opt clauseBody-opt
clauseHead,
lowercaseIdentifier ( term-comma-sep-list-opt )
returnValue,
= term
clauseBody,
,- term
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 37
12.4.2 目标段
目标段是一个程序的入口。当程序开始执行时,首先从目
标段开始执行,目标段被执行完后,程序就退出。
goalSection,
goal term,
目标段由一个子句体组成。目标段定义了它自身的作用
域,因此所有的调用都应当包含类的限定符。
通常,目标必须是过程模式 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 38
本节介绍事实 ( Facts) 的有关内
容, 包括事实段 ( Facts Sections),
事实声明 ( Fact Declarations),
事实变量 ( Fact Variables) 等 。
12.5 事实
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 39
12.5.1 事实段
一个事实段声明一个由若干事实组成的事实数据库。该
事实数据库及事实属于当前作用域。
事实数据库可以存在于类级别上,也可以存在于对象级
别上。
事实段只能在类实现中进行声明。
factsSection,
class-opt facts factsSectionName-opt factDeclaration-
dot-term-list-opt
factsSectionName,
- lowerCaseIdentifier
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 40
12.5.2 事实声明
事实声明用于声明一个事实数据库的事实。事实声明也是一个事实变
量或一个事实算符。
factDeclaration,
factVariableDeclaration
factFunctorDeclaration
factFunctorDeclaration,
factName, ( argument-comma-sep-list-opt ) factMode-opt
factName,
lowerCaseIdentifier
一个事实算符声明缺省为 nondeterm事实模式。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 41
12.5.2 事实声明
一个事实算符可以通过子句段进行初始化 。 在这种情况下, 子句中的
值应当是表达式, 这些表达式可以在编译时间内进行求值 。
factMode, one of
determ nondeterm single
如果模式为 single,那么一个事实就有一个值并且只有一个值, 而且
谓词 assert会给原来的值赋新的值 。 谓词 retract不用于单个事实 。
如果模式为 nondeterm,那么这一事实就可以有 0个,1个或任意其
它个值。如果模式为 determ,那么事实可以有 0或 1个值。如果事实有 0
个值,那么任何读操作都会失败。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 42
12.5.3 事实变量
一个事实变量与一个一元单个事实算符类似。但是,从语法上讲,它作为可
变变量(即以赋值方式)使用。
factVariableDeclaration,
factVariableName, domain initialValue-opt
initialValue,
,= constantValue
factVariableName,
lowerCaseIdentifier
一个常量值 constantValue应当是一个项 ( 论域类型的 ), 可以在编
译时间求值 。
只要在一个构造器中将事实变量初始化,那么常量值就可以省略。类
事实变量应当总有一个初始的常量值。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 43
12.5.3 事实变量
注意, 关键字 erroneous可被用来将其值赋给事实变量 。
下面两行是有效的,
facts
thisWin, vpiDomains::windowHandle,= erroneous,
clauses
p(),- thisWin,= erroneous,
用 erroneous赋值的基本思想,是为了在某些代码错误地
使用了未初始化的事实时,给出一个明确的运行时间错误。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 44
12.5.4 事实
事实只能在类实现中进行声明,并且以后它们只能从这个实现被引用。
因此事实的作用域就是它们被声明的这个实现。但是对象事实的生命期
是它所属的对象的生命期。同样地,类事实的生命期是从程序开始到程
序结束。
举例
下面的类声明了一个对象事实 objectFact和一个类事实 classFact,
implement aaa_class
facts
objectFact, (integer Value) determ,
class facts
classFact, (integer Value) determ,
,.,
end implement aaa_class
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 45
12.6 评估
评估( Evaluation)又称为求值运算。 Visual
Prolog通过执行目标来实现。
目标是一个项。本节叙述项和子句的执行或计
算是怎样进行的,包括回溯( Backtracking)、
谓词调用、合一( unification)、引用论域、匹
配、嵌套的函数调用、变量与常量、算术表达式、
事实断言与撤消等。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 46
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
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 47
12.6.1 回溯
一个 Prolog程序的评估或运算是搜索求解的过程。搜
索求解的每一步或者成功或者失败。在程序执行的特定点
上,有可能不止有一种解决方案。当遇到这样的选择点时,
就建立所谓的回溯点。一个回溯点是程序状态的一个记录,
即添加一个指针到未执行的选择点。如果它证明了初始的
选择不能提供解决方案(即失败),那么程序将回溯到记
录过的回溯点,从而恢复程序状态和追踪另一个选择。在
下面的部分还将对该机制进行详细描述和解释。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 48
12.6.2 谓词调用
通过使用参数到一个谓词实现该谓词的调用。该谓词必
须有一个流模式,以匹配参数的自由或绑定状态。每个谓词
由一个子句集合(或在外部用某种其它语言)定义。
当谓词被谓词调用引用时,每个子句依次执行直到它们
成功,或直到没有子句可执行为止。如果没有子句成功,那
么该谓词失败。
如果一个子句成功并且还剩有其他的有关子句,那么程
序控制可以在以后回溯到剩余的子句,以搜索其它的解。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 49
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中的第二个子句实际执行之前,第
三个子句的回溯点已经建立好了。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 50
12.6.3 合一
当一谓词被调用时,来自调用的参数与每个子句的子句头的项合一。
合一是绑定变量的过程,在这一过程中,两项通过尽可能少的绑定达
到相等(即为进一步绑定留下尽可能多的开放空间)。
变量可以绑定为各种项,包括变量或含有变量的项。
合一有时可能有时不可能,也就是说它可能成功也可能失败。
变量和与其合一的项是有类型的,一个变量只能被绑定到与它类型相
同的项或子类型上。当两个变量互相绑定时,它们就必须是完全相同的
类型。
如上所述,合一发生在一个谓词调用和子句头之间,也发生在比较两
项是否相等之时。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 51
12.6.3 合一
举例
考虑类型相同的两项,
T1 = f1(g(),X,17,Y,17)
T2 = f1(Z,Z,V,U,43)
我们打算从左至右合一这两项。
T1和 T2都是 f1/5项,这是匹
配。因此打算将 T1中的参数与
T2中相应的参数进行合一。
首先必须合一 Z和 g(),产生了合一器中的第一
个绑定,
Z = g()
其次是 X和 Z,其中 Z已经被绑定到 g()。 如果将
X也绑定到 g(),那么这两个参数也可以合一 。
因此现在对于合一器有如下的新增内容,
X = Z = g()
再次, 必须将 V绑定为 17,然后将 Y绑定到 U。
再合并到合一器中得,
X = Z = g(); V = 17; Y = U
现在这两个合一的项等同于下面的项,
T1 = f1(g(),g(),17,Y,17)
T2 = f1(g(),g(),17,Y,43)
结论:最后两个参数 17和 43不能进行合一, 所以合一失败 。 T1和 T2不能合一 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 52
12.6.4 引用论域
下面举例说明引用论域的概念和用法。
举例
考虑类型相同的两项,
T1 = f1(g(),X,17,Y)
T2 = f1(Z,Z,V,U)
这些项可以依照以下合一器进行合一,
X = Z = g()
V = 17
Y = U
并且合一后的项如下,
f1(g(),g(),17,Y)
这一项包括一个自由变量 Y(它正好绑定到 U)。如果项的类型为引用论域,
那么它们只能是自由变量。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 53
12.6.5 匹配
对于不是引用论域类型的项不需要进行完全彻底的合一,用匹配就足
够了。如果该项包括引用论域类型的子项,那么这些子项必须合一而不
是匹配。
除了变量只能被绑定到基础( grounded)项之外,匹配与合一是相
同的。一个基础项是不包含任何自由变量的项。
为谓词声明适当的流模式,就有可能使用匹配而不是完全彻底地进行
合一。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 54
12.6.5 匹配
举例
clauses
ppp(Z,Z,17),
qqq(),-
ppp(g(),X,17),
ppp调用与 ppp子句的合一可能使用下面的合一器,
Z = X = g()
如果 ppp有流模式 (i,o,i),那么合一就是一个匹配,
* g()作为第一个参数输入,绑定到 Z
* 子句中的第二个参数因此被绑定;这样输出 X,X被绑定到 g()。
* 最后第三个参数 17作为输入, 这个数字只是与子句中的第三个参数
进行比较 。
只有通过流模式才能预测子句不需要真正合一的可能性。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 55
12.6.6 嵌套的函数调用
彼此必须相互合一或匹配的项允许包含子项,这些子项实际上是那
些必须在合一或匹配完成之前进行求值计算的表达式或函数调用。这样
的子项求值计算建立在需要的基础上。
在谓词调用中,所有输入参数均在调用发生前进行计算,所有输出参
数均为变量,不需要计算。
在匹配或合一能被确定之前,子句头也可以包含必须计算的项。
总的说来,基本原则是,
* 输入在另一匹配之后,在子句体计算之前;
* 输出在子句体计算之后;
* 从左至右。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 56
12.6.7 变量与常量
Prolog中的变量是不可变的,一旦被绑定了一个值就会保持该值,除非利用
回溯在恢复先前程序状态的过程中重新释放这个变量。
一个变量可以在合一和匹配时被绑定,如果它已经被绑定,那么可以经过计
算得出它所绑定的值。
变量名以大写字母或下划线开头,后面可以跟任意多个字母(大小写均
可)、数字或下划线字符。例如,下面的变量名是合法的,
My_first_correct_variable_name
_
_Sales_10_11_86
下面两个变量名是非法的,
1stattempt
second_attempt
一个常量( Constants)表示它被定义的值。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 57
12.6.8 算术表达式
算术表达式( Arithmetic Expressions)按算术运算符中所描述
的运算符级别进行分析。对于二元表达式先计算左边的项,再计算右
边的项。
相等 ( =)
首先计算等式左边的项,然后计算右边的项,最后它们相互合一。
合一常常
可以简化为匹配。
比较
首先计算左边的项,然后计算右边的项,最后比较结果。
注意:不等号( <>或 ><)不是等号( =)的对偶运算。 <>比较
两个值,而
=是将两项合一(至少在大多数情况下)。
表达式 A=B的对偶表达式为 not(A=B)。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 58
12.6.9 事实断言与撤消
事实变量( Fact Variables)是可变变量,它们计算已经
赋予它们的值。
一个新值可以通过赋值的方法赋给一个事实变量。
一个事实数据库包括若干完全用具体例证说明的谓词头,
该谓词头与来自事实段定义的事实相对应。这些事实可以通
过用事实名作为谓词名的谓词调用来访问。该谓词调用依次
与每个事实相匹配;每当该谓词调用与事实相匹配时,后面
就会跟一个下一事实可能的回溯点。当事实数据库中不再有
事实时,该谓词调用失败。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 59
12.6.10 失败谓词和成功谓词
失败谓词 fail/0和成功谓词 succeed/0是两个内
建的空变元谓词。 fail/0总是失败而 succeed/0总是
成功,此外它们并无任何影响。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 60
12.6.11 逻辑与
逻辑“与 (and)”,在程序的子句体中常用逗号表示。一个,and”表
达式,A,B”按如下步骤进行处理。首先计算左子项 A。如果这一计算失
败,整个,and”项失败。如果 A成功则接着计算右子项。如果计算失败,
则整个,and”项失败,否则,and”项成功。因而,只有在第一子项 A成
功的情况下,第二子项 B才会得到计算。
举例
clauses
ppp(),-
qqq(),rrr(),
当 ppp被调用时,它首先调用 qqq,如果 qqq成功,则调用 rrr。如果
rrr成功,则,and”项成功,随后即整个子句成功。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 61
12.6.12 逻辑或
逻辑“或( or)”,在程序的子句体中常用分号表示。一个,or”表
达式,A;B”按如下步骤进行处理。首先创建一个指向第二项 B的回溯点,
然后计算第一项 A。如果第一项计算成功,则整个,or”项成功,留下
一指向第二项 B的回溯点。如果第一项的计算失败,则指向第二项的回
溯点被激活。
如果指向第二项的回溯点被激活(因第一项失败或在后面执行的某
项操作中调用了回溯点),则第二项 B被计算,若 B成功,则整个,or”
项成功。
因而一个, or”项可以在一个回溯点上获得成功, 而第二子项 B只在
回溯过程中得到计算 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 62
12.6.12 逻辑或
举例
clauses
ppp(),-
qqq(V),write(V),fail,
qqq(X),-
X = 3 ; X = 7,
因为创建了回溯点, 回溯也使所有变量绑定失效 。 在这种情况下, 意味
着 ppp中的 V及 qqq中的 X都是非绑定变量 。 然后, X=7在 qqq中得到计
算, X因而绑定到 7,控制回到 ppp,X绑定到 7并被打印输出 。 接着再次
出现失败, 这次 ppp中没有更多的回溯点, 所以 ppp失败 。
当 ppp被调用时, 它首先调用 qqq。 qqq
先创建一个指向 X=7的回溯点, 然后计
算 X=3。 qqq返回 。 因为 ppp中的 V绑定
为 3,V被打印输出为 3,然后出现 fail。
fail总是失败, 因此控制权被设定在 qqq
的回溯点上 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 63
12.6.13 逻辑非
逻辑“非( not)”,not/1以一个项作为参数。对 not(A)的计算首
先计算 A。如果 A成功,则 not(A)失败,如果 A失败,则 not(A)成功。
注意,not(A)不绑定任何变量, 因为若 not(A)成功, 则 A失败, 一个
失败的变量不绑定任何量;另一方面, 若 not(A)失败, 它同样不能绑定
任何变量, 因为该项本身失败 。
另外,not(A)也不能跟任何回溯点,因为若 not(A)成功,则 A失败,而
一个失败的项不能包含任何回溯点。这也意味着 A中所有成功的可能性
都没有了。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 64
12.6.14 截断( Cut)
截断,在程序中常用感叹号, !, 表示。截断会删除从当前谓词入口
处开始创建的所有回溯点,这是指所有指向后来子句的回溯点,再加上
截断之前的当前子句的谓词调用中安置的回溯点。
举例
clauses
ppp(X),-
X > 7,
!,
write("Greater than seven"),
ppp(_X),-
write("Not greater than seven"),
当 ppp被执行时,有一个首次
创建的指向第二子句的回溯点,
然后第一子句被执行。如果测
试, X>7”成立,则截断(, !”)
是可到达的。这一截断, !”将
取消指向第二子句的回溯点。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 65
12.6.14 截断( Cut)
举例
clauses
ppp(),-
qqq(X),
X > 7,
!,
write("Found one"),
ppp(),-
write("Did not find one"),
clauses
qqq(3),
qqq(12),
qqq(13),
当 ppp被执行时, 它首先创建一个指向第
二个 ppp子句的回溯点, 然后调用 qqq。
qqq将创建一个指向第二个 qqq子句的回
溯点并执行第一子句, 从而返回值 3。 在
ppp中, 变量 X绑定为 3这个值然后与 7比
较 。 测试失败, 因而控制回溯至 qqq的第
二子句 。
在执行第二子句前, 指向 qqq的第三子句
的回溯点被创建, 然后第二子句返回 12。
这次与 7的比较测试成立, 因而执行截断 。
这一截断将删除 qqq中留下的回溯点和指
向 ppp中第二子句的回溯点 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 66
12.6.15 谓词 finally/2
finally/2是一个特殊的内部谓词,它以两个子项作为参数。无论第
一项的计算结果如何,它确保对第二项的计算。如果满足以下条件,则
必然计算第二项,
* 第一项成功
* 第一项失败
* 第一项意外终止
整个项表现如下,
* 如果第一项成功,那么整个项的表现就像用 "and"连接了两项一样;
* 如果第一项失败, 则整个项失败 ( 在完成第二项的计算之后 ) ;
* 如果第一项意外终止, 则整个项也将意外终止 ( 在完成第二项的计
算之后 ) 。
如果第二项意外终止, 则整个项将意外终止 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 67
12.6.15 谓词 finally/2
举例
clauses
ppp(),-
Resource = allocateExternalResource(),
finally(
use(Resource),
deallocateExternalResource(Resource )),
这个例子是 finally/2谓词的典型应用 。 不论资源使用的结
果如何, 外部分配的资源必须被释放 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 68
12.7 程序段
程序段( Program Sections)用来声明和定义作用域内的实体。
section,
constantsSection
domainsSection
predicatesSection
constructorsSection
factsSection
clausesSection
conditionalSection
不是所有的段都能在各种作用域中出现。更为详尽的内容请参考接口、
类声明和类实现。
条件段在条件编译中介绍。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 69
第十二章小结
本章介绍 Visual Prolog的程序元素,内容包括项( Terms)、常
量、谓词、子句、事实、运算、程序段等。
第十二章习题
1,Visual Prolog程序元素包含那些内容?分析每一项的含义。
2、阅读下面的程序,找出程序中的错误。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 70
第十二章习题
程序如下,
PREDICATES
likes_shopping(symbol)
has_credit_card(symbol,symbol)
bottomed_out(symbol,symbol)
CLAUSES
likes_shopping(Who):-
has_credit_card(Who,Card),
not(bottomed_out(Who,Card)),
write(Who," can shop with the ",Card," credit card.\n"),
has_credit_card(chris,visa),
has_credit_card(chris,diners),
has_credit_card(joe,shell),
has_credit_card(sam,mastercard),
has_credit_card(sam,citibank),
bottomed_out(chris,diners),
bottomed_out(sam,mastercard),
bottomed_out(chris,visa),
goal
likes_shopping(Who),
2004.11.1 AI程序设计 1
第 12章 Visual Prolog程序元素
12.1 项
12.2 常量
12.3 谓词
12.4 子句
12.5 事实
12.6 评估
12.7 程序段
本章小结
本章习题
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 2
12.1 项
本章介绍 Visual Prolog的程序元素,内
容包括项( Terms)、常量、谓词、子句、
事实、运算、程序段等。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 3
12.1.1 项的基本概念
项有两种类型:公式 formulas和表达式 expressions。
表达式代表数值,比如数字 7;公式代表逻辑声明,比如
,数字 7比数字 3大, 。
下面是项的简化定义,其中包括非法的语法结构。例
如,! + !的书写形式是不合法的。但是,相信在和语言概
念的直觉理解相结合时,使用这样的简化语法表示,在大多
数情况下对于类型系统和运算符层次结构的描述更为有利。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 4
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,
!
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 5
谓词调用
一个谓词调用形式如下,
predicateCall,
term ( term-comma-sep-list-opt )
首项必须直接声明调用谓词的名字。就是说,首项必须
是一个谓词名,一个限定谓词名或一个成员访问。
注意, 有些谓词有返回值, 有些则没有返回值 。 如果一个
谓词有返回值, 这个值就必须在上下文中使用, 不能被忽
略 。
12.1.1 项的基本概念
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 6
事实赋值
赋值操作符,= 用于向事实变量 factVariable赋予一个
新值 。 项 term必须被赋于一个适当类型 ( 即与事实变量或子
类型相同的类型 ) 的值 。
factVariableAssignment,
factVariable,= term
12.1.1 项的基本概念
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 7
12.1.2 运算符
运算符( Operators)按优先层次进行组织。在规则中,下面各组中
的操作符具有相同的优先权,并且上面的操作符比下面的优先级高。就
是说,一元加减法要比乘法运算符优先级高,而乘法运算符又比加法运
算符高。圆括号可以改变运算优先级。
unaryOperator,
- +
binaryOperator,
multiplicationOperator
additionOperator
relationOperator
andOperator
orOperator
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 8
12.1.2 运算符
12.1.2.1 算术运算符
算术运算符 ( Arithmetic Operators) 用于数字的算术运算 。 它们是
表达式, 用表达式作为参数 。 它们采用根类型作为参数, 并返回通用类
型的结果 。 ( 参见通用类型和根类型 ) 所有的算术操作符都是左结合的
( left associative) 。
multiplicationOperator,one of
* / div mod
additionOperator,one of
+ -
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 9
12.1.2 运算符
12.1.2.2 关系运算符
关系运算符 ( Relational Operators) 是公式, 用表达式作
参数 。 它们从本质上是无关联的 。
relationOperator,one of
> < > = <= <> >< =
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 10
12.1.2 运算符
12.1.2.3 逻辑运算符
逻辑运算符 ( Logical Operators) 主要包括逻辑, 与 ( and),, 逻辑
,或 ( or), 及逻辑, 非 ( not), 运算符等 。 逻辑, 与, 运算符
andOperator和逻辑, 或, 运算符 orOperator是公式, 用公式作参数 。
它们是左结合的 。 ","和 " and "是同义词, " ; " 和 " or "也是同义词 。
andOperator,one of
,and
orOperator,one of; or
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 11
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"关系项。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 12
12.1.3 类成员访问
类实体通过限定类名的方式进行访问,
qualifiedName,
identifier,,identifier
这样的限定名像普通的名字一样使用,即如果它是一个谓
词,它就可以用于一个参数集。
有些名字访问不需要限定,参见有关作用域的内容。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 13
12.1.4 对象成员访问
每当引用一个对象时, 都可以访问该对象的对象成员谓词 。
memberAccess,
term, identifier
(目前, 项 term必须是一个变量或一个事实变量 )
标识符 identifier必须是项 term的类型 。
在一个实现内部,对象成员谓词不需要引用对象就可以
被调用,因为 "This"已经被包含在其中了。参见有关作用域
的内容。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 14
12.1.5 全局实体的访问
存在于 Visual Prolog中的仅有的全局实体是类、接口和
内部论域、谓词、常量。全局名在任意作用域内都可以直接
访问。也可能存在全局名与局域名或输入名重合的情况。在
这种情况下,全局实体可以用双冒号‘,:’来限定(不带前缀
的类名或接口名)。双冒号可以随处使用,但是最重要的用
处还是接口名用作形式参数类型说明符的情况。
globalName,
,,identifier
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 15
12.1.6 论域、算符和常量访问
论域、算符和常量都像类成员一样被访问。即
便它们在一个接口中被声明。
这就是说,当它们要被限定的时候,就总是
以类或接口名加双冒号来限定。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 16
本节介绍常量 ( Constant) 的有关概念,
内容包括常量段, 常量定义等 。
12.2 常量
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 17
12.2.1 常量段
一个常量段( Constants Section)定义了当前作
用域内的常量集。
constantsSection,
constants constantDefinition-dot-term-list-opt
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 18
12.2.2 常量定义
常量定义( Constant Definitions)声明一个命名的常量,包括它的
类型和值。
constantDefinition,
constantName, typeName = constantValue
constantName,
lowerCaseIdentifier
常量值 constantValue是一个表达式, 在编译时间内计算 。 常量名
ConstantName应该是一个小写标识符 lowerCaseIdentifier。
如果一个类型名 typeName论域是一个标准论域, 那么它和冒号 ', '可
以被省略, 得到以下简写形式,
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 19
12.2.2 常量定义
constantDefinition,
constantName = constantValue
以这样的方式定义的常量可以用于所有的上下文中, 在这里可以使用
与其同一种类的文字 。
如果类型名 typeName被省略, 那么常量论域必须明确地被常量值表
达式确定 。 仅在下列内部论域情况下, typeName才能被省略 。
a) 数字 ( 整数或实数 ) 常量 。 在这种情况下, 相应的匿名数字论域被
采纳为常量 ( 详细情况参见数字论域 )
b) 二进制常量 。
c) 字符串常量 。
d) 字符常量 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 20
12.3 谓词
本节介绍谓词( Predicates)的有关概念,
内容包括谓词段( Predicates Sections)、构造
段( Constructors Sections)、接口谓词
( Predicates from Interface)、谓词的元
( Arity)等。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 21
12.3.1 谓词段
谓词段声明当前作用域内的对象或类谓词的集合。
predicatesSection,
class-opt predicates predicateDeclaration-dot-term-list-opt
关键字 class只能在类实现内部使用,这是因为在接口
中声明的谓词永远是对象谓词;在类声明中声明的谓词永
远是类谓词。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 22
12.3.1 谓词段
谓词声明
类声明用于声明作用域中的谓词, 在作用域中这些谓词是可见的 。 当谓词
在一个接口定义中被声明时, 就是说相应类型的对象必须支持这些谓词 。 当谓
词在类声明中被定义时, 就是说该类提供所声明的公用谓词 。 并且, 如果谓词
在类的实现中被声明的话, 那么该谓词就在局部可用 。 在所有的情况下, 必须
存在谓词的相应定义 。
predicateDeclaration,
predicateName, predicateDomain linkName-opt
predicateName, predicateDomainName linkName-opt
linkName,
as stringLiteral
predicateName,
lowerCaseIdentifier
这里 predicateDomainName是在论域段声明的谓词论域名 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 23
12.3.1 谓词段
一个谓词声明, 声明了该谓词的名称以及类型, 模式,
流 ( 参见谓词论域 ) 和可选的一个连接名 。
只有类谓词可以有连接名 。 如果没有声明连接名, 那么就
从谓词名取连接名, 取名的方式取决于调用约定 。
如果调用约定是 apicall,那么 as子句中所声明的连接名就
可以采用任意方式修饰;如果该修饰不是所要的, 则用
stdcall代替 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 24
12.3.2 构造段
构造段声明了构造器的集合。这些构造器属于所出现的构
造段的作用域(参见类声明和类实现)。
constructorsSection,
constructors constructorDeclaration-dot-term-list-opt
构造段只能出现在构造对象的类的声明和实现当中。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 25
12.3.2 构造段
构造声明
构造声明用于声明类的已命名的构造器 。
实际上, 构造器包含两个相关谓词 。
* 一个类函数,返回一个新的被构建的对象;
* 一个对象谓词, 在初始化继承对象时使用 。
一个相关的对象谓词构造器用于执行一个对象的初始化 。 该谓词只能
从该类自身的构造器或是该类的继承类的构造器中调用 ( 即基本的类初
始化 ) 。
constructorDeclaration,
constructorName, predicateDomain
给构造器声明谓词模式是非法的,构造器总是过程模式的 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 26
12.3.2 构造段
举例
考虑下面的类,
class test_class, test
constructors
new, (integer Argument),
end class test_class
相关的类级的谓词形式如下 ( 有以下标志 ),
class predicates
new, (integer) -> test,
而相关的对象级的谓词形式如下,
predicates
new, (integer),
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 27
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"的一次调用 。
第二次调用返回一个值, 因此它是对类的构造器的函数调用 。 就是说, 创建了一
个新的对象 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 28
12.3.3 接口谓词
一个接口能够通过在 predicates from段声明的谓词来支持另一接口的子
集。 predicates from 段指定接口和所有支持的谓词。这些谓词以名字或者名
字和元数来声明。
如果一个接口支持另一个接口的子集,那么它就不是与另外那个接口相关的
子类型或超类型。
关于 predicates from段重要的是,所提及的谓词保留它们的原始接口。因
此,
* 来自原始接口的任意谓词不会发生支持冲突;
* 它们能够作为来自原始接口的谓词被继承。
predicatesFromInterface,
predicates from interfaceName predicateNameWithArity-
comma-sep-list-opt
predicatesFromInterface只能在接口定义中被使用。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 29
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,将其作为原始接口。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 30
12.3.3 接口谓词
举例
interface aaa
predicates
ppp, (),
qqq, (),
end interface aaa
interface bbb
predicates from aaa
ppp
predicates
rrr, (),
end interface bbb
class aaa_class, aaa
end class aaa_class
class bbb_class, bbb
end class bbb_class
implement aaa_class inherits bbb_class
clauses
qqq(),
end implement aaa_class
aaa_class 可 以 从
bbb_class继承 ppp,因为
ppp在两个类中都含有 aaa,
并将其作为原始接口 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 31
12.3.4 变元
使用 N个参数的谓词被称为 N元谓词( N-ary),或者说该谓词有 N个
变元。所含变元数不同的谓词,即使它们名称相同,通常也是不同的谓
词。
在大多数情况下,一个谓词的元数在包含该谓词的上下文中是明显的。
但是,在某些情况,比如,接口谓词段 predicatesFromInterface段和
resolve限定中,变元数并不明显。
为了区别 predicates from 段和 resolve限定中不同变元数的谓词,
谓词名可以选择采用带有变元数的声明。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 32
12.3.4 变元
下列变元数是可能的,
· Name/N 指一个普通谓词 (即不是一个函数 )的名字,变元个数为
N;
· Name//N 指一个函数名, 变元个数为 N;
· Name/N..,指一个带 N个变元的普通谓词名, 后跟一个省略参数
(即个数可改变的参数 )
Name//N..,指一个带 N个变元的函数名, 后跟一个省略参数 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 33
12.3.4 变元
predicateNameWithArity,
predicateName arity-opt
arity,
/ integerLiteral ellipsis-opt
// integerLiteral ellipsis-opt
在 Name/0..,和 Name//0..,中, 0是可选项, 因此它们可以分别写作
Name/..,和 Name//...。
注意, 省略号 "…"可以作为最后一个形式参数用于谓词和谓词论域的声
明 。 在这种情况下, 就是指所声明的谓词 ( 或谓词论域 ) 的参数个数是
可改变的 。 省略流必须与一个省略参数匹配, 因此只能是流模式中的最
后一个流 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 34
12.4 子句
本节介绍子句( Clauses)的有关内容,
包括子句段( Clauses Sections)、目标
段( Goal Sections)等。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 35
12.4.1 子句段
子句段由子句集组成。子句段包括谓词的实现或事实的初始化值。
一个单独的子句段可以含有几个谓词和事实的子句。另一方面,同一
谓词或事实(同名并变元数相同)的所有子句必须集中在一个子句段中,
并且不涉及其它谓词或事实的子句。
clausesSection,
clauses clause-dot-term-list-opt
子句用于定义谓词。单一的谓词由一个子句集定义。每个子句依次执
行,直到其中一个子句成功,或没有子句可执行为止。如果没有子句成
功,该谓词失败。
如果一个子句成功,并且在一个谓词的剩余部分有更多相关子句,那
么程序控制将在以后回溯到该谓词的子句,以查找其它的解决方案。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 36
12.4.1 子句段
子句由一个子句头( head)和一个可选的子句体( body)组成。
clause,
clauseHead returnValue-opt clauseBody-opt
clauseHead,
lowercaseIdentifier ( term-comma-sep-list-opt )
returnValue,
= term
clauseBody,
,- term
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 37
12.4.2 目标段
目标段是一个程序的入口。当程序开始执行时,首先从目
标段开始执行,目标段被执行完后,程序就退出。
goalSection,
goal term,
目标段由一个子句体组成。目标段定义了它自身的作用
域,因此所有的调用都应当包含类的限定符。
通常,目标必须是过程模式 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 38
本节介绍事实 ( Facts) 的有关内
容, 包括事实段 ( Facts Sections),
事实声明 ( Fact Declarations),
事实变量 ( Fact Variables) 等 。
12.5 事实
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 39
12.5.1 事实段
一个事实段声明一个由若干事实组成的事实数据库。该
事实数据库及事实属于当前作用域。
事实数据库可以存在于类级别上,也可以存在于对象级
别上。
事实段只能在类实现中进行声明。
factsSection,
class-opt facts factsSectionName-opt factDeclaration-
dot-term-list-opt
factsSectionName,
- lowerCaseIdentifier
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 40
12.5.2 事实声明
事实声明用于声明一个事实数据库的事实。事实声明也是一个事实变
量或一个事实算符。
factDeclaration,
factVariableDeclaration
factFunctorDeclaration
factFunctorDeclaration,
factName, ( argument-comma-sep-list-opt ) factMode-opt
factName,
lowerCaseIdentifier
一个事实算符声明缺省为 nondeterm事实模式。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 41
12.5.2 事实声明
一个事实算符可以通过子句段进行初始化 。 在这种情况下, 子句中的
值应当是表达式, 这些表达式可以在编译时间内进行求值 。
factMode, one of
determ nondeterm single
如果模式为 single,那么一个事实就有一个值并且只有一个值, 而且
谓词 assert会给原来的值赋新的值 。 谓词 retract不用于单个事实 。
如果模式为 nondeterm,那么这一事实就可以有 0个,1个或任意其
它个值。如果模式为 determ,那么事实可以有 0或 1个值。如果事实有 0
个值,那么任何读操作都会失败。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 42
12.5.3 事实变量
一个事实变量与一个一元单个事实算符类似。但是,从语法上讲,它作为可
变变量(即以赋值方式)使用。
factVariableDeclaration,
factVariableName, domain initialValue-opt
initialValue,
,= constantValue
factVariableName,
lowerCaseIdentifier
一个常量值 constantValue应当是一个项 ( 论域类型的 ), 可以在编
译时间求值 。
只要在一个构造器中将事实变量初始化,那么常量值就可以省略。类
事实变量应当总有一个初始的常量值。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 43
12.5.3 事实变量
注意, 关键字 erroneous可被用来将其值赋给事实变量 。
下面两行是有效的,
facts
thisWin, vpiDomains::windowHandle,= erroneous,
clauses
p(),- thisWin,= erroneous,
用 erroneous赋值的基本思想,是为了在某些代码错误地
使用了未初始化的事实时,给出一个明确的运行时间错误。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 44
12.5.4 事实
事实只能在类实现中进行声明,并且以后它们只能从这个实现被引用。
因此事实的作用域就是它们被声明的这个实现。但是对象事实的生命期
是它所属的对象的生命期。同样地,类事实的生命期是从程序开始到程
序结束。
举例
下面的类声明了一个对象事实 objectFact和一个类事实 classFact,
implement aaa_class
facts
objectFact, (integer Value) determ,
class facts
classFact, (integer Value) determ,
,.,
end implement aaa_class
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 45
12.6 评估
评估( Evaluation)又称为求值运算。 Visual
Prolog通过执行目标来实现。
目标是一个项。本节叙述项和子句的执行或计
算是怎样进行的,包括回溯( Backtracking)、
谓词调用、合一( unification)、引用论域、匹
配、嵌套的函数调用、变量与常量、算术表达式、
事实断言与撤消等。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 46
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
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 47
12.6.1 回溯
一个 Prolog程序的评估或运算是搜索求解的过程。搜
索求解的每一步或者成功或者失败。在程序执行的特定点
上,有可能不止有一种解决方案。当遇到这样的选择点时,
就建立所谓的回溯点。一个回溯点是程序状态的一个记录,
即添加一个指针到未执行的选择点。如果它证明了初始的
选择不能提供解决方案(即失败),那么程序将回溯到记
录过的回溯点,从而恢复程序状态和追踪另一个选择。在
下面的部分还将对该机制进行详细描述和解释。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 48
12.6.2 谓词调用
通过使用参数到一个谓词实现该谓词的调用。该谓词必
须有一个流模式,以匹配参数的自由或绑定状态。每个谓词
由一个子句集合(或在外部用某种其它语言)定义。
当谓词被谓词调用引用时,每个子句依次执行直到它们
成功,或直到没有子句可执行为止。如果没有子句成功,那
么该谓词失败。
如果一个子句成功并且还剩有其他的有关子句,那么程
序控制可以在以后回溯到剩余的子句,以搜索其它的解。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 49
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中的第二个子句实际执行之前,第
三个子句的回溯点已经建立好了。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 50
12.6.3 合一
当一谓词被调用时,来自调用的参数与每个子句的子句头的项合一。
合一是绑定变量的过程,在这一过程中,两项通过尽可能少的绑定达
到相等(即为进一步绑定留下尽可能多的开放空间)。
变量可以绑定为各种项,包括变量或含有变量的项。
合一有时可能有时不可能,也就是说它可能成功也可能失败。
变量和与其合一的项是有类型的,一个变量只能被绑定到与它类型相
同的项或子类型上。当两个变量互相绑定时,它们就必须是完全相同的
类型。
如上所述,合一发生在一个谓词调用和子句头之间,也发生在比较两
项是否相等之时。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 51
12.6.3 合一
举例
考虑类型相同的两项,
T1 = f1(g(),X,17,Y,17)
T2 = f1(Z,Z,V,U,43)
我们打算从左至右合一这两项。
T1和 T2都是 f1/5项,这是匹
配。因此打算将 T1中的参数与
T2中相应的参数进行合一。
首先必须合一 Z和 g(),产生了合一器中的第一
个绑定,
Z = g()
其次是 X和 Z,其中 Z已经被绑定到 g()。 如果将
X也绑定到 g(),那么这两个参数也可以合一 。
因此现在对于合一器有如下的新增内容,
X = Z = g()
再次, 必须将 V绑定为 17,然后将 Y绑定到 U。
再合并到合一器中得,
X = Z = g(); V = 17; Y = U
现在这两个合一的项等同于下面的项,
T1 = f1(g(),g(),17,Y,17)
T2 = f1(g(),g(),17,Y,43)
结论:最后两个参数 17和 43不能进行合一, 所以合一失败 。 T1和 T2不能合一 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 52
12.6.4 引用论域
下面举例说明引用论域的概念和用法。
举例
考虑类型相同的两项,
T1 = f1(g(),X,17,Y)
T2 = f1(Z,Z,V,U)
这些项可以依照以下合一器进行合一,
X = Z = g()
V = 17
Y = U
并且合一后的项如下,
f1(g(),g(),17,Y)
这一项包括一个自由变量 Y(它正好绑定到 U)。如果项的类型为引用论域,
那么它们只能是自由变量。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 53
12.6.5 匹配
对于不是引用论域类型的项不需要进行完全彻底的合一,用匹配就足
够了。如果该项包括引用论域类型的子项,那么这些子项必须合一而不
是匹配。
除了变量只能被绑定到基础( grounded)项之外,匹配与合一是相
同的。一个基础项是不包含任何自由变量的项。
为谓词声明适当的流模式,就有可能使用匹配而不是完全彻底地进行
合一。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 54
12.6.5 匹配
举例
clauses
ppp(Z,Z,17),
qqq(),-
ppp(g(),X,17),
ppp调用与 ppp子句的合一可能使用下面的合一器,
Z = X = g()
如果 ppp有流模式 (i,o,i),那么合一就是一个匹配,
* g()作为第一个参数输入,绑定到 Z
* 子句中的第二个参数因此被绑定;这样输出 X,X被绑定到 g()。
* 最后第三个参数 17作为输入, 这个数字只是与子句中的第三个参数
进行比较 。
只有通过流模式才能预测子句不需要真正合一的可能性。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 55
12.6.6 嵌套的函数调用
彼此必须相互合一或匹配的项允许包含子项,这些子项实际上是那
些必须在合一或匹配完成之前进行求值计算的表达式或函数调用。这样
的子项求值计算建立在需要的基础上。
在谓词调用中,所有输入参数均在调用发生前进行计算,所有输出参
数均为变量,不需要计算。
在匹配或合一能被确定之前,子句头也可以包含必须计算的项。
总的说来,基本原则是,
* 输入在另一匹配之后,在子句体计算之前;
* 输出在子句体计算之后;
* 从左至右。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 56
12.6.7 变量与常量
Prolog中的变量是不可变的,一旦被绑定了一个值就会保持该值,除非利用
回溯在恢复先前程序状态的过程中重新释放这个变量。
一个变量可以在合一和匹配时被绑定,如果它已经被绑定,那么可以经过计
算得出它所绑定的值。
变量名以大写字母或下划线开头,后面可以跟任意多个字母(大小写均
可)、数字或下划线字符。例如,下面的变量名是合法的,
My_first_correct_variable_name
_
_Sales_10_11_86
下面两个变量名是非法的,
1stattempt
second_attempt
一个常量( Constants)表示它被定义的值。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 57
12.6.8 算术表达式
算术表达式( Arithmetic Expressions)按算术运算符中所描述
的运算符级别进行分析。对于二元表达式先计算左边的项,再计算右
边的项。
相等 ( =)
首先计算等式左边的项,然后计算右边的项,最后它们相互合一。
合一常常
可以简化为匹配。
比较
首先计算左边的项,然后计算右边的项,最后比较结果。
注意:不等号( <>或 ><)不是等号( =)的对偶运算。 <>比较
两个值,而
=是将两项合一(至少在大多数情况下)。
表达式 A=B的对偶表达式为 not(A=B)。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 58
12.6.9 事实断言与撤消
事实变量( Fact Variables)是可变变量,它们计算已经
赋予它们的值。
一个新值可以通过赋值的方法赋给一个事实变量。
一个事实数据库包括若干完全用具体例证说明的谓词头,
该谓词头与来自事实段定义的事实相对应。这些事实可以通
过用事实名作为谓词名的谓词调用来访问。该谓词调用依次
与每个事实相匹配;每当该谓词调用与事实相匹配时,后面
就会跟一个下一事实可能的回溯点。当事实数据库中不再有
事实时,该谓词调用失败。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 59
12.6.10 失败谓词和成功谓词
失败谓词 fail/0和成功谓词 succeed/0是两个内
建的空变元谓词。 fail/0总是失败而 succeed/0总是
成功,此外它们并无任何影响。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 60
12.6.11 逻辑与
逻辑“与 (and)”,在程序的子句体中常用逗号表示。一个,and”表
达式,A,B”按如下步骤进行处理。首先计算左子项 A。如果这一计算失
败,整个,and”项失败。如果 A成功则接着计算右子项。如果计算失败,
则整个,and”项失败,否则,and”项成功。因而,只有在第一子项 A成
功的情况下,第二子项 B才会得到计算。
举例
clauses
ppp(),-
qqq(),rrr(),
当 ppp被调用时,它首先调用 qqq,如果 qqq成功,则调用 rrr。如果
rrr成功,则,and”项成功,随后即整个子句成功。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 61
12.6.12 逻辑或
逻辑“或( or)”,在程序的子句体中常用分号表示。一个,or”表
达式,A;B”按如下步骤进行处理。首先创建一个指向第二项 B的回溯点,
然后计算第一项 A。如果第一项计算成功,则整个,or”项成功,留下
一指向第二项 B的回溯点。如果第一项的计算失败,则指向第二项的回
溯点被激活。
如果指向第二项的回溯点被激活(因第一项失败或在后面执行的某
项操作中调用了回溯点),则第二项 B被计算,若 B成功,则整个,or”
项成功。
因而一个, or”项可以在一个回溯点上获得成功, 而第二子项 B只在
回溯过程中得到计算 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 62
12.6.12 逻辑或
举例
clauses
ppp(),-
qqq(V),write(V),fail,
qqq(X),-
X = 3 ; X = 7,
因为创建了回溯点, 回溯也使所有变量绑定失效 。 在这种情况下, 意味
着 ppp中的 V及 qqq中的 X都是非绑定变量 。 然后, X=7在 qqq中得到计
算, X因而绑定到 7,控制回到 ppp,X绑定到 7并被打印输出 。 接着再次
出现失败, 这次 ppp中没有更多的回溯点, 所以 ppp失败 。
当 ppp被调用时, 它首先调用 qqq。 qqq
先创建一个指向 X=7的回溯点, 然后计
算 X=3。 qqq返回 。 因为 ppp中的 V绑定
为 3,V被打印输出为 3,然后出现 fail。
fail总是失败, 因此控制权被设定在 qqq
的回溯点上 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 63
12.6.13 逻辑非
逻辑“非( not)”,not/1以一个项作为参数。对 not(A)的计算首
先计算 A。如果 A成功,则 not(A)失败,如果 A失败,则 not(A)成功。
注意,not(A)不绑定任何变量, 因为若 not(A)成功, 则 A失败, 一个
失败的变量不绑定任何量;另一方面, 若 not(A)失败, 它同样不能绑定
任何变量, 因为该项本身失败 。
另外,not(A)也不能跟任何回溯点,因为若 not(A)成功,则 A失败,而
一个失败的项不能包含任何回溯点。这也意味着 A中所有成功的可能性
都没有了。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 64
12.6.14 截断( Cut)
截断,在程序中常用感叹号, !, 表示。截断会删除从当前谓词入口
处开始创建的所有回溯点,这是指所有指向后来子句的回溯点,再加上
截断之前的当前子句的谓词调用中安置的回溯点。
举例
clauses
ppp(X),-
X > 7,
!,
write("Greater than seven"),
ppp(_X),-
write("Not greater than seven"),
当 ppp被执行时,有一个首次
创建的指向第二子句的回溯点,
然后第一子句被执行。如果测
试, X>7”成立,则截断(, !”)
是可到达的。这一截断, !”将
取消指向第二子句的回溯点。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 65
12.6.14 截断( Cut)
举例
clauses
ppp(),-
qqq(X),
X > 7,
!,
write("Found one"),
ppp(),-
write("Did not find one"),
clauses
qqq(3),
qqq(12),
qqq(13),
当 ppp被执行时, 它首先创建一个指向第
二个 ppp子句的回溯点, 然后调用 qqq。
qqq将创建一个指向第二个 qqq子句的回
溯点并执行第一子句, 从而返回值 3。 在
ppp中, 变量 X绑定为 3这个值然后与 7比
较 。 测试失败, 因而控制回溯至 qqq的第
二子句 。
在执行第二子句前, 指向 qqq的第三子句
的回溯点被创建, 然后第二子句返回 12。
这次与 7的比较测试成立, 因而执行截断 。
这一截断将删除 qqq中留下的回溯点和指
向 ppp中第二子句的回溯点 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 66
12.6.15 谓词 finally/2
finally/2是一个特殊的内部谓词,它以两个子项作为参数。无论第
一项的计算结果如何,它确保对第二项的计算。如果满足以下条件,则
必然计算第二项,
* 第一项成功
* 第一项失败
* 第一项意外终止
整个项表现如下,
* 如果第一项成功,那么整个项的表现就像用 "and"连接了两项一样;
* 如果第一项失败, 则整个项失败 ( 在完成第二项的计算之后 ) ;
* 如果第一项意外终止, 则整个项也将意外终止 ( 在完成第二项的计
算之后 ) 。
如果第二项意外终止, 则整个项将意外终止 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 67
12.6.15 谓词 finally/2
举例
clauses
ppp(),-
Resource = allocateExternalResource(),
finally(
use(Resource),
deallocateExternalResource(Resource )),
这个例子是 finally/2谓词的典型应用 。 不论资源使用的结
果如何, 外部分配的资源必须被释放 。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 68
12.7 程序段
程序段( Program Sections)用来声明和定义作用域内的实体。
section,
constantsSection
domainsSection
predicatesSection
constructorsSection
factsSection
clausesSection
conditionalSection
不是所有的段都能在各种作用域中出现。更为详尽的内容请参考接口、
类声明和类实现。
条件段在条件编译中介绍。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 69
第十二章小结
本章介绍 Visual Prolog的程序元素,内容包括项( Terms)、常
量、谓词、子句、事实、运算、程序段等。
第十二章习题
1,Visual Prolog程序元素包含那些内容?分析每一项的含义。
2、阅读下面的程序,找出程序中的错误。
第三部分:第 12章 Visual Prolog 程序元素
2004.11.1 AI程序设计 70
第十二章习题
程序如下,
PREDICATES
likes_shopping(symbol)
has_credit_card(symbol,symbol)
bottomed_out(symbol,symbol)
CLAUSES
likes_shopping(Who):-
has_credit_card(Who,Card),
not(bottomed_out(Who,Card)),
write(Who," can shop with the ",Card," credit card.\n"),
has_credit_card(chris,visa),
has_credit_card(chris,diners),
has_credit_card(joe,shell),
has_credit_card(sam,mastercard),
has_credit_card(sam,citibank),
bottomed_out(chris,diners),
bottomed_out(sam,mastercard),
bottomed_out(chris,visa),
goal
likes_shopping(Who),