知识库操作
先说个小伎俩。
在VIP中打开geni.prj,菜单选Options,打开Application Expert,点击Other Options,
点击Project Directories,点击Output,在Final文本框填入d:\Apache2.2\htdocs\GENI
这个目录是GENI虚拟主机所在之处。
这样做的目的,是编译后geni.exe会自动存入上述目录,省去了人工搬运的麻烦。
开始今天的话题,进行知识库操作。
下一步是执行GOAL段的子句consult_kb(ParmList,ParmList1)。
这个子句的流模式是(i,o),也就是说,ParmList已被约束,
值为[parm("knowledgebase","animal")],
而ParmList1是*变量,未被约束,值为空。
子句consult_kb(ParmList,ParmList1)比较简单直观。
consult_kb([parm("knowledgebase",KB)|Rest],Rest):- assert(kb(KB)), filenameext(Name,KB,".gni"), syspath(ExeStartupPath,_ProgName), filenamepath(FullName,ExeStartupPath,Name), consult(FullName,geni),!. consult_kb(_,[]):- errorexit.
稍作解释。
consult_kb([parm("knowledgebase",KB)|Rest],Rest)
子句头部值得关注的有4点:
第1点,头部匹配条件[parm("knowledgebase",KB)|Rest]为:
第一参数是个列表,其中第一个成员是复合结构parm,parm的第一参数是"knowledgebase"
第2点,头部的KB和Rest,只是输出变量,不是子句头部匹配条件
KB和Rest在此亮相,是为了在子句体内使用
第3点,变量的匹配、合一。
第二参数变量的值,约束为Rest。
第4点,若头部匹配失败,不执行子句体内的语句。
assert(kb(KB))
把知识kb(KB)存入VIP内部数据库(事实库)
assert()是VIP内建谓词。
kb()的声明是:
DATABASE - tmp determ kb(STRING)在此,关键字determ确定,事实库里只许有一条kb()事实。
KB的值是"animal"。
KB不能是*变量(空值),否则,assert()运行出错。
filenameext(Name,KB,".gni")
它是VIP内建谓词。
它有2种流模式(i, o, o), (o, i, i),本例是第2种。
结果,Name="animal.gni"
若是第1种流模式,如:filenameext("animal.gni",Name,Ext)
结果,Name="animal",Ext=".gni"
流模式的不同,使得Prolog的同一子句,具有多种功能。
syspath(ExeStartupPath,_ProgName)
它是VIP内建谓词,流模式是(o, o) 。
它返回本程序的名称及其所在目录。
本例第二参数 _ProgName,下划线表明它是个“匿名变量”,未被使用。
filenamepath(FullName,ExeStartupPath,Name)
它是VIP内建谓词,流模式是(i, o, o), (o, i, i) 。例如:
(i, o, o)模式下 FullName = "d:\\apache2.2\\htdocs\\geni\\animal.gni" 则子句filenamepath返回: Path = "d:\\apache2.2\\htdocs\\geni\\" Name = "animal.gni" (o,i,i)模式下 Path = "d:\\apache2.2\\htdocs\\geni\\" Name = "animal.gni" 则子句filenamepath返回: FullName = "d:\\apache2.2\\htdocs\\geni\\animal.gni"
consult(FullName,geni)
它是VPI内建谓词。流模式是(i, i) 。
从文本文件中,读出“事实”,存入程序的事实库。
第二参数geni,是事实库的名字。
DATABASE - geni rule(RNO,CATEGORY,CATEGORY,CONDITIONS,STRING) cond(CNO,STRING,STRING OPTIONS) topic(STRING maingoal,STRING purpose) head(STRING headline, STRING helptopic) default_startpage(STRING FILENAME)
知识库文件animal.gni中的事实名称,符合事实段geni的要求。
rule(1,"carnivore","cheetah",[1,2],"animals\\cheetah.htm") …… cond(1,"it has tawny color","animals\\animals.htm") …… topic("animal","I will try to guess which animal you are thinking of") default_startpage("animal.htm")
errorexit ()
生成一个运行时刻错误,和内部出错信息。
出错信息编号1000
内容是"Program error! Check source code at reported position"
consult_kb的运行机制:回溯与截断
先看它的形式结构:
consult_kb(……):- ……, ……, ……. consult_kb(……):- …….
这样的简化,有助于突出重点,理解关键。
注意!这个谓词由2个子句构成。
第一个子句,我特意暂时省略了运算符“!”
回溯的前提条件,是谓词由2个以上子句构成。
回溯的发生,有以下2种情况。
1、第一子句体内语句执行发生失败(fail),引起第二子句执行
2、第一子句体内语句执行成功,但没有设置“截断”,
其他谓词子句的失败,导致回溯到本谓词的第二子句重试
“截断”情况是这样的:
consult_kb(……):- ……, ……, ……, !. consult_kb(……):- …….
用运算符“!”设置截断。
本例把截断设置在最后一行的目的是:
1、第一子句体内的语句,只要发生失败,即引起回溯,执行第二子句;
2、第一子句体内的语句,全部成功后,消除回溯点,
其他谓词子句引起的回溯,不会涉及本谓词子句。