首页 > 代码库 > Visual Prolog 的 Web 专家系统 (4)

Visual Prolog 的 Web 专家系统 (4)

知识库操作

先说个小伎俩。
在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、第一子句体内的语句,全部成功后,消除回溯点,
其他谓词子句引起的回溯,不会涉及本谓词子句。