永无止境的填充方法,返回答案但不退出的无限循环

时间:2015-05-09 20:52:38

标签: list prolog

所以我正在做一些prolog,并且遇到了一个我不明白为什么会出现的问题。这个问题实际上发生在我的一些方法中,但希望我能用这个方法中的一些指导来解决它。

RewriteBase /

这是我的代码

fill(3,a,L) -> L = [a,a,a]

1 个答案:

答案 0 :(得分:2)

第一个条款应该是:

fill(0, _, []).

您的代码留下一个选择点(对于您的示例查询):当计数器达到零时,两个子句头与当前目标统一。只有尝试使用第二个子句,才能达到N1 >= 0目标。此目标将失败(此时N1-1)。因此,第二个条款将无法提供替代解决方案。但Prolog解释器在找到第一个解决方案时并不知道。因此,提出了第一个解决方案,然后Prolog顶级解释器等待您的输入。键入返回通常意味着您不希望Prolog推理引擎回溯并寻找替代解决方案。如果您输入一个分号,“;”,您将要求其他解决方案。

您可以将fill/3谓词更改为不离开选择点。一个快速的解决方案是在第一个子句中添加一个剪切“!/ 0”:

fill(0, _, []) :-
    !.
fill(N, A, [A| As]) :-
    N > 0,
    N1 is N - 1,
    fill(N1, A, As).

切割是一个令人讨厌的小虫子,它始终是真的,但它用于它的副作用:扔掉选择点。

上面快速解决方案的一个问题是,削减通常会使代码减少声明并引入微妙(而不是那么微妙的错误)。在这种情况下,有一个明显更好的解决方案:只需交换两个子句的顺序:

fill(N, A, [A| As]) :-
    N > 0,
    N1 is N - 1,
    fill(N1, A, As).
fill(0, _, []).

只有在第一个子句中的N > 0测试失败时才会尝试第二个子句。但请注意,并非所有Prolog 顶级解释器都检测到查询没有(更多)解决方案。

但是这个解决方案也有自己的问题,这取决于Prolog系统以及它如何索引或不索引索引。你能发现它吗?我会给你一个提示:空间复杂性。