永无止境的填充方法,returns回答但不退出的无限循环
Never-ending fill method, infinite loop that returns answer but doesn't exit
所以我正在写一些序言,运行 遇到了一个我不明白为什么会出现的问题。这个问题实际上发生在我的一些方法中,但希望我可以通过这个方法中的一些指导来解决它。
fill(3,a,L) -> L = [a,a,a]
这是我的代码
fill(0,x,[]).
fill(N,A,[A | As]) :-
N1 is N-1,
fill(N1,A,As).
第一个子句应该是:
fill(0, _, []).
您的代码留下了一个选择点(对于您的示例查询):当计数器达到零时,两个子句头与当前目标统一。只有尝试使用第二个子句,才能达到 N1 >= 0
的目标。这个目标将失败(因为此时 N1
是 -1
)。因此,第二个条款将无法提供替代解决方案。但是当 Prolog 解释器找到第一个解时,它并不知道。因此,首先给出解决方案,然后 Prolog 顶层解释器等待您的输入。输入 return 通常意味着您不希望 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 系统及其索引或不索引子句的方式。你能发现吗?我会给你一个提示:space复杂性。
所以我正在写一些序言,运行 遇到了一个我不明白为什么会出现的问题。这个问题实际上发生在我的一些方法中,但希望我可以通过这个方法中的一些指导来解决它。
fill(3,a,L) -> L = [a,a,a]
这是我的代码
fill(0,x,[]).
fill(N,A,[A | As]) :-
N1 is N-1,
fill(N1,A,As).
第一个子句应该是:
fill(0, _, []).
您的代码留下了一个选择点(对于您的示例查询):当计数器达到零时,两个子句头与当前目标统一。只有尝试使用第二个子句,才能达到 N1 >= 0
的目标。这个目标将失败(因为此时 N1
是 -1
)。因此,第二个条款将无法提供替代解决方案。但是当 Prolog 解释器找到第一个解时,它并不知道。因此,首先给出解决方案,然后 Prolog 顶层解释器等待您的输入。输入 return 通常意味着您不希望 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 系统及其索引或不索引子句的方式。你能发现吗?我会给你一个提示:space复杂性。