Prolog 递归中的回溯如何不导致无限循环?
假设member/2谓词定义为:Prolog 递归中的回溯如何不导致无限循环?,prolog,Prolog,假设member/2谓词定义为: member(X,[X|R]). member(X,[Y|R]) :- member(X,R). 我的问题是: member(X, [1, 2, 3]). 一旦prolog将X与1统一起来,如果我键入,prolog如何获得其他可能的统一? 难道不可以先从序言中回溯,然后从上到下重新读取包含成员定义的文件,并再次计算member(X[X | R])。这会再次将X与1统一起来吗?您所述的规则是: 成员(X[X|R])。 “管道”操作符将列表的第一个元素与列表的其
member(X,[X|R]).
member(X,[Y|R]) :- member(X,R).
我的问题是:
member(X, [1, 2, 3]).
一旦prolog将X与1统一起来,如果我键入,prolog如何获得其他可能的统一代码>?
难道不可以先从序言中回溯,然后从上到下重新读取包含成员定义的文件,并再次计算member(X[X | R])。
这会再次将X与1统一起来吗?您所述的规则是:
成员(X[X|R])。
“管道”操作符将列表的第一个元素与列表的其余元素分开。所以,如果列表是[1,2,3]
,X=1
,和R=[2,3]
。
X
是[X | R]
列表(即第一个成员)的car
因此,在本例中,成员(1[1,2,3])。
是true
成员(X[Y | R]):-成员(X,R)。
第二种情况涉及列表的第一个成员与X不同的情况。如果是这样,则调用成员(X,R)
,并检查列表的cdr
(即从第二个元素开始)
因此,成员(1[1,2,3])。
不会触发递归
例如,当元素不在列表中时会发生什么
为简洁起见,成员(1,[2])。
是true
还是false
这属于第二条规则,因为X=1
不同于Y=2
但是,列表的cdr
是一个空列表(即,在第一个元素旁边没有任何元素)
所以member(1,[2]):-member(1,[])。
,而这个member(1,[])
求值总是false。
Prolog的输出:
~ $ swipl
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.
For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).
?- [user].
|: member(X, [X | L]) :- write('Evaluated first clause with X='), write(X), write('.'), nl.
|: member(X, [Y | L]) :- write('Evaluated second clause with X='), write(X), write(' and Y='), write(Y), write('.'), nl, member(X, L).
|: end_of_file.
% user://1 compiled 0.01 sec, 2 clauses
true.
?- member(1, [1, 2, 3]).
Evaluated first clause with X=1.
true .
?- member(2, [1, 2, 3]).
Evaluated second clause with X=2 and Y=1.
Evaluated first clause with X=2.
true .
?- member(4, [1, 2, 3]).
Evaluated second clause with X=4 and Y=1.
Evaluated second clause with X=4 and Y=2.
Evaluated second clause with X=4 and Y=3.
false.
?- X=1, member(X, [1, 2, 3]).
Evaluated first clause with X=1.
X = 1 .
(省略警告)。这个怎么样
注意以下几点:
- 程序被读取一次,然后留在内存中,等待用户输入查询(与数据库场景相同)
- 当它执行时,它会在内存中构建一个“搜索树”
- 遇到的每个谓词的OR节点:任何分支(对应于该谓词的子句)都必须为TRUE
- 遇到的每个子句体都有一个AND节点:所有分支(与
,
分隔的子句体中的调用相对应)都必须为TRUE
- 当程序可以“在树的底部退出”并且
- 在任何AND节点下,所有分支都为TRUE
- 在任何OR节点下,至少有一个分支为TRUE(在Prolog中,OR节点下只有一个“活动分支”)
- 如果找不到这样的树,程序最终会失败(这可能需要一些时间)
- 程序成功后,树将保持活动状态,以防用户要求“更多解决方案”
- 如果您要求“更多解决方案”,将在底部重新输入树,并尝试其他分支
以及:
- 变量名是子句的局部变量
- 变量内容(如果他们说“变量未绑定”,则为术语或没有内容的单元格)始终是全局的。如果树中较深的节点“细化”其变量之一的内容,则此更改在树的最顶端节点可见(尽管是在另一名称或另一术语的一部分下)
“第二种情况涉及列表中第一个成员与X不同的情况”-不,不是这样。它不关心统一第一个元素。第二种情况只是忽略第一个元素,使其能够递归调用列表其余部分的谓词。您可以在swi prolog上进行测试。链式规则是。仅第二条规则是不够的。我还觉得调用cdrnull
也是错误的。Prolog要么统一,要么不统一,因此[X]
不能与[\u124; Y]
统一,因为Prolog希望Y
是一个非空列表。这不是真的。它不包括第一个元素与X
不同的情况。它根本不关心X
的值是多少。您应该使用文件的end\u,而不是使用^D(Ctrl-D)。
()