PROLOG程序没有完全编译,而是由WAM解释。因此,可以在运行时修改程序。程序甚至可以自我修改。使用诸如断言和撤销之类的命令,可以将事实和规则添加到知识库中或从中获取。
变体断言的一个简单应用是在知识库的开头添加派生事实,目的是避免重复的,潜在的时间昂贵的推导(参见第 81 页的练习 5.8 )。如果在我们的家庭关系示例中,我们用谓词替换谓词后代的两个规则
1.
:
– 动态后代/ 2。
2.
后代(X,Y): – 子(X,Y,Z),断言(后代(X,Y))。
3.
后代(X,Y): – 子(X,U,V),后代(U,Y),
4.
asserta的(后裔(X,Y))。
然后,该谓词的所有派生事实都保存在知识库中,因此将来不会重新派生。查询
? – 后裔(克莱德,卡伦)。
导致两个事实的增加
后裔(克莱德,卡伦)。后裔(玛丽,凯伦)。
通过使用assert和retract操作规则,甚至可以编写完全自我更改的程序。这个想法在术语“ 基因编程”中已为人所知。它允许构建任意灵活的学习计划。然而,在实践中,事实证明,由于大量无意义的可能变化,通过反复试验来改变代码很少会导致性能提升。另一方面,系统地改变规则使编程变得更加复杂,到目前为止,广泛修改自己的代码的程序还没有成功。在Chap。8我们将展示机器学习是如何取得成功的。但是,这里只对程序代码进行非常有限的修改。
5.
开始: – 动作(状态(左,左,左,左),
6.
状态(右,右,右,右))。3
4动作(开始,目标): –
10计划(开始,目标,访问,路径): –
15计划(目标,目标,路径,路径)。16
7.
去(州(X,X,Z,K),州(Y,Y,Z,K)): – 跨(X,Y)。%农夫,狼
8.
去(州(X,W,X,K),州(Y,W,Y,K)): – 跨(X,Y)。%农民,山羊
9.
去(州(X,W,Z,X),州(Y,W,Z,Y)): – 跨(X,Y)。%农民,白菜
10.
去(州(X,W,Z,K),州(Y,W,Z,K)): – 跨(X,Y)。%农民21
11.
跨越(左,右)。
13.
安全(状态(B,W,Z,K)): – 跨(W,Z),跨(Z,K)。
14.
安全的(状态(B,B,B,K))。
计划(接下来,目标,[下一页|访问],路径)。
%not(成员(…))
去(开始,下一步),安全(下一步),
+成员(下一步,访问过),
11
12
13
14
%所有解决方案输出
write_path(Path),失败。
plan(Start,Goal,[Start],Path),nl,write(‘Solution:‘),nl,write_path(Path)。
五
6
7
8%
9
图5.4 农民 – 狼 – 山羊 – 卷心菜问题的PROLOG程序