Prolog 人工智能语言中文论坛---打造优质Prolog学习交流园地

一个供Prolog爱好者学习与交流的地方


您没有登录。 请登录注册

提高程序的效率---妙用截断Cut(以感叹号"!"表示)

浏览上一个主题 浏览下一个主题 向下  留言 [第1页/共1页]

善用截断(Cut),以"!"表示,有时能够大大提高程序效率,
减少不必要的流程,
有些时候,不使用Cut甚至会使程序久久跑不出结果,甚至爆堆栈(Stack)。
所以当你的程序跑得很慢,或久久跑不出结果,或显示Out of Stack时,
记得检查一下什么地方应该适当加上"!"减少程序负荷。


下面我们来看一个例子:

代码:
fact(1).
fact(2).
fact(3).
fact(4).
fact(5).


print_fact(X) :- fact(F), F >= X, write(F), fail.
print_fact(_) :- write(6).

查询 ?- print_fact(2).
传回
23456
true.


可以看到fact(F)匹配1时,1 >= 2失败,所以并没有write,
回溯时fact(F)匹配到2,这次2 >= 2成功,程序继续执行右边的句子,
将2 write出来,但随即遇到fail强迫其失败,再次回溯……
一直印到5之后,还是被强迫fail,
程序转往检替同名的另一个谓词print_fact(_)
(注意"_"为匿名变量,作用是:其实你写X、Y、YY只要是变量都可以,只是名字叫什么不重要,所以以"_"代替),
这句很简单,直接write出6,并且成功,返回true。

如果我只需要一个答案就够了(这个例子是指2),
我可以在fail前加个"!",
"!"的作用是:
1. 禁止"!"左边的所有句子产生回溯。讲白话一点,禁止左边的句子找超过1个答案。
2. 禁止和谓词(此例为print_fact)同名的回溯。讲白话一点,程序不去执行任何与print_fact(X)同名的谓词。
(注意如果print_fact(A,B)这种不叫做和print_fact(X)同名,所有print_fact/1才算同名)。

我们来试一下:
将print_fact(X)改成
代码:
print_fact(X) :- fact(F), F >= X, write(F),! , fail.

?- print_fact(2).
2
false.

程序只印出2,超过一个答案的345被省略了,下一句print_fact(_)也被省了,
所以6也没印出来。

注意:F = 1匹配成功后,1 >= 2失败,所以"!"没被执行,
因此fact(F)还是进行了1次回溯去匹配到2,并不是只要出现在"!"左边就会被截断,要看"!"有无被执行。
前面讲的截断规则是建立在"!"被执行的基础上。


把"!"换个位置,按照前面所讲的规则,你应该能猜出结果吧?
将print_fact(X)改成
代码:
print_fact(X) :- !, fact(F), F >= X, write(F), fail.

?- print_fact(2).
2345
false.

可以看到,在"!"右边的句子不会受到影响,2345依然印出来,
但下一句同名的谓词还是被截断的,所以6没有印出来。

查阅用户资料 http://prolog.longluntan.net

浏览上一个主题 浏览下一个主题 返回页首  留言 [第1页/共1页]

您在这个论坛的权限:
不能在这个论坛回复主题