Prolog递归和终止

时间:2012-02-16 20:20:37

标签: recursion prolog

第一个StackOverflow问题。

我在prolog中编写了一个带有三个参数的谓词。它们(分别)是一个字符,一个字符串列表,最后一个参数是第二个参数中以第一个参数开头的所有字符串的列表。我的写作陈述代替了我完全缺乏关于如何在SWI-Prolog中追踪的知识。无论如何,关于代码!


startString(C, [H1|T1], [H2|T2]) :-
    atom_chars(H1, [C| _ ]),
    H2 = H1,
    startString(C, T1, T2).

startString(C, [ _ |T1], Y) :-
    startString(C, T1, Y),
    write(foo).

startString(_, [], []) :-
    write(foo).

哪个输出:


foofoofoo

X = [some, simple]

我的方法是正确的,但谓词并没有终止(在写X之后缺少句号不是错误)。我的问题是,为什么不呢?从我在互联网上找到的递归的有限例子来看,我的谓词的第三个版本应该终止谓词并使x成为明确的答案。

当我按回车键时,我可以输入另一个查询,但我有同样的问题"问题"在我在同一个程序中写的另一个谓词中。对这个谓词的任何帮助也应该延续到另一个。谢谢!

2 个答案:

答案 0 :(得分:3)

要在评论中将您的问题扩展到@ScottHunter,

  

我想我的问题是,为什么我的其他谓词“知道”他们有正确的答案,而这还有一个没有?

答案与堆栈上选择点的存在有关。考虑一下这种情况:

reasonably_big(L, X) :- member(X, L), X > 100.

?- reasonably_big([105, 2], X).
X = 105 ;
false.
?-

将其与此相比:

?- reasonably_big([2, 105], X).
X = 105.
?-

在第二种情况下,Prolog“知道”没有更多的解决方案;在第一种情况下,它没有。这两种情况之间的区别在于,在第一种情况下member在堆栈上留下了选择点:列表中还有另一个项目可以考虑找到另一个答案。在第二种情况下,列表的其余部分是空的,并且SWI-Prolog的member非常聪明,在这种情况下不会在堆栈上留下选择点,因此它从未询问您是否需要其他解决方案。 / p>

如果您获得无关的选择点,通常会指出逻辑错误。例如,请考虑min

的定义
min(X, Y, X) :- X =< Y.
min(X, Y, Y).

这是有缺陷的,因为你总是可以回溯并获得其他价值;说:

?- min(3,4, X).
X = 3 ;
X = 4.

第二种解决方案是错误的。但是,通过做出错误的改进,你仍然可以找到一个不必要的选择点:

min(X, Y, X) :- X =< Y.
min(X, Y, Y) :- Y =< X.

看看当我们尝试不同的值时会发生什么:

?- min(4,3,X).
X = 3.
?-

?- min(3,4,X).
X = 3 ;
false.
?-

第一个工作正常,但第二个通过拥有第二个身体在堆叠上留下了一个选择点。你可以用绿色切割消除它:

min(X,Y,X) :- X =< Y, !.
min(X,Y,Y) :- Y =< X.

?- min(3,4,X).
X = 3.
?-

?- min(4,3,X).
X = 3.
?-

剪切将Prolog提交给特定解决方案。它说,一旦你在这里做到了,就没有必要为这个谓词尝试任何其他解决方案,因为我们找到了我们想要的唯一解决方案。了解如何应用剪切是一个复杂的主题,但消除不良选择点是一个重要的用途。

答案 1 :(得分:1)

你必须小心你在Prolog中“终止”的意思。当你要求prolog证明startString('s',some-list,X)时你有一个绑定到X的值的事实意味着它终止了(否则它仍然会搜索X的值)。但在另一种意义上它没有,因为你可以问(通常通过进入分号)Prolog尝试找到另一种解决方案,并且可以继续询问,直到它耗尽了这样做的可能性。听起来你的控制台正在等着你告诉它你是否想要尝试找到另一种解决方案,或者你已经完成了(当你点击输入时会发生这种情况,而解释器允许你输入一个新的查询)。 / p>