Visual Prolog 的 Web 专家系统 (8)

GENI的核心 -- 推理机(2)流程控制

1、细说fail、“!”与回溯

与其他语言相比,Prolog最大的特点,是它的回溯机制。

回溯机制,主要手段有2个,一是用谓词fail引发回溯,二是用特别谓词“!”(读作cut)取消回溯。

Prolog运用fail引发回溯,实现程序的循环,并运用“!”对回溯进行控制。

看一个典型示例:

FACTS
	f(integer)
PREDICATES
	a()
	b()
	c()
CLAUSES
	a():-
		write("------ a -------\n"),
		f(X),
		writef("%\n",X),
		fail.
	a():-
		write("a is sucsess.").
%---------------------------------------------------------
	b():-
		write("\n\n------- b -------\n"),
		f(X),
		writef("%\n",X),
		!,
		fail.
	b():-
		write("b is sucsess.").
%---------------------------------------------------------
	c():-
	        write("\n\n------- c -------\n"),
		a(),
		b(),
		!,
		write("\nc sucsess.").
	c():-
		write("\nc backtracking.\n\n").
%---------------------------------------------------------
GOAL
assert(f(1)),
assert(f(2)),
assert(f(3)),
c().

在VDE中,菜单选:File|New,新建一文件noname.pro,把上边的代码贴进去

菜单选:Project|Test Goal,

运行结果,输出显示如下:


------- c -------
------ a -------
1
2
3
a is sucsess.

------- b -------
1

c backtracking.

yes

程序很简单,GOAL先把事实f(1)、f(2)、f(3)入库,接着查询c()。

Prolog把“函数调用”称作“求证(query)子目标”。

并非Prolog矫情,别的“小语种”基本如此。

比如,函数语言Lisp、Erlang等,把“函数调用”称作“求值(evaluate)“。

还得说说”子目标“。

从理论上说,Prolog程序,由一个总目标和多个子目标构成,形成”树“逻辑关系。

GOAL是总目标,即树的根结点,子目标则是树的各层枝叶

在本示例中,总目标的子目标是c(),而a(),b()则是c()的子目标。

在a()和b()中,子目标是f(X)。

这段示例代码的看点,主要是fail!

write(),writef()等管理输入输出的谓词,不是子目标。因为,它们不参与求证、推理。

要正确理解谓词子句体内子目标的关系,逗号”,“是关键。

逗号”,“的含意,是逻辑”与“,and。因此,子句体实际上是个复合逻辑判断:

例如,子句 

a():- b(),c(),d().

相当于:

if a() then {  if (b() and c() and d()) then a() }

这里并没写错,子句头与子句体就是这样的逻辑关系。

不仅如此,分号”;“表示逻辑”或“。例如,本例的谓词a(),2个子句可以合并写成这样:

	a():-
		write("------ a -------\n"),
		f(X),
		writef("%\n",X),
		fail
		;
		write("a is sucsess.").

只是,用分号”,“而非并列子句表示逻辑或,会造成代码难读、难懂误会,很不实用。

所以,在实际编程中,几乎见不到使用分号”;“的。

现在再回到GENI的推理机流程控制这个话题上来。

上面提到的“典型示例”,是GENI的推理机流程控制的方法之一。

其中,谓词a()中的fail,遍历了全部f(X);

谓词b()中的 !,fail,只取得第一个f(X),并且不再回溯;

谓词c()中的 ! 也很重要。没有它,程序编译时就会出错。

Prolog
您的回应...

相关话题

查看全部

也许你感兴趣

换一批

热门标签

更多