【问题标题】:Prolog infinite loop issueProlog无限循环问题
【发布时间】:2014-11-09 20:10:49
【问题描述】:

我有以下功能。 当我用final_filter([(2, 2)], R) 调用它时,它会打印很多“2 2”对。当我评论get_all_sums(S, _) 时,它工作正常,但是如果我单独测试get_all_sums(4, R)。我的工作也很好,可能是什么问题?

get_all_sums_R(NR, IT, []):- IT > NR - 2.
get_all_sums_R(NR, IT, R):-
    A is IT,
    B is NR-IT,
    A >= B,
    NEXT_IT is IT + 1,
    get_all_sums_R(NR, NEXT_IT, R_NEXT),
    append([(A, B)], R_NEXT, R).
get_all_sums_R(NR, IT, R):-
    A is IT,
    B is NR-IT,
    A < B,
    NEXT_IT is IT + 1,
    get_all_sums_R(NR, NEXT_IT, R).

get_all_sums(NR, R):-get_all_sums_R(NR, 2, R).


get_all_divisors(X, IT, []):-IT > X/2.
get_all_divisors(X, IT, R):-
    IT =< X/2,
    TMP_RES is mod(X, IT),
    TMP_RES =:= 0,
    NEXT_IT is IT + 1,
    get_all_divisors(X, NEXT_IT, R_NEXT),
    append([IT], R_NEXT, R).
get_all_divisors(X, IT, R):-
    IT =< X/2,
    NEXT_IT is IT + 1,
    get_all_divisors(X, NEXT_IT, R).

get_all_products_R([], _, []).
get_all_products_R([H|L], NR, R):-
    A is H,
    B is NR/H,
    A >= B,
    get_all_products_R(L, NR, NEXT_R),
    append([(A, B)], NEXT_R, R).
get_all_products_R([H|L], NR, R):-
    A is H,
    B is NR/H,
    A < B,
    get_all_products_R(L, NR, R).

get_all_products(NR, R):-
    get_all_divisors(NR, 2, R_LEFT),
    get_all_products_R(R_LEFT, NR, R).

single_element([_]).

final_filter([(A, B)|_], _):-
    write(A),
    P is A*B,
    S is A+B,
    get_all_products(P, PRODUCTS),
    get_all_sums(S, _),
    write(A),write(' '), write(B), write('\n'),
    not(single_element(PRODUCTS)).

【问题讨论】:

  • 你期待什么? get_all_sums(S, _). 产生实例化错误,get_all_sums(4, R), false 不会终止
  • 我试过了 %d:/newl 编译了 0,00 秒,14 个子句 1 ?- get_all_sums(4, R)。 R = [ (2, 2)] 。 2 ?- get_all_sums(4, _)。真的。

标签: prolog failure-slice


【解决方案1】:

这里的核心误解是终止在 Prolog 中的含义。即通用终止。感兴趣的查询如下:

?- get_all_sums(4,R).
R = [ (2, 2)] 

Prolog 的顶级外壳首先为您提供了一个单一的答案。但是您可以通过输入 ; 或 SPACE 获得更多。因此,在向您展示第一个答案/解决方案时,Prolog 还没有完成。事实上:

?- get_all_sums(4,R).
R = [ (2, 2)] ;
R = [ (2, 2), (3, 1)] ;
R = [ (2, 2), (3, 1), (4, 0)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1), (6, -2)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1), (6, -2), (7, -3)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1), (6, -2), (7, -3), (8, -4)] ;
R = [ (2, 2), (3, 1), (4, 0), (5, -1), (6, -2), (7, -3), (8, -4), (9, -5)] ...

您真的要枚举所有负数吗?在我看来是无限的!

但是让我们只关注非终止属性......

也许系统会在 8 个解决方案后停止?有没有更好的方法 当然?只需按如下方式“关闭”解决方案的显示:

?- get_all_sums(4,R), false.

现在我们不再对解决方案/答案感到恼火,我们可以只专注于终止属性。我将进一步添加此类目标 false 和更多内容到您的程序中,以本地化未终止的实际原因。生成的程序称为故障片。而且无论我如何添加false 目标,它始终认为:如果失败切片没有终止,那么原始程序也不会终止。经过一番尝试,我得到:

get_all_sums_R(NR, IT, []):- false, IT > NR - 2。 get_all_sums_R(NR, IT, R):- NR = 4, A是IT, B是NR-IT, A >= B, NEXT_IT 是 IT + 1, get_all_sums_R(NR, NEXT_IT, R_NEXT), 假, 追加([(A,B)],R_NEXT,R)。 get_all_sums_R(NR, IT, R):- false, A 是 IT, B 是 NR-IT, A, NEXT_IT 是 IT + 1, get_all_sums_R(NR, NEXT_IT, R)。 get_all_sums(NR, R):-get_all_sums_R(NR, 2, R), false。 ?- get_all_sums(4, R), false。

所以这个小剩余部分负责不终止。为了解决这个问题,您必须在此处添加一些目标。可以肯定的是:NR = 4,A 增加 1,B 减少 1。而且只要A &gt;= B,这个循环就会继续下去。

您可能想在某处添加剪辑或once/1。但是这个 只会将您从一个错误引导到另一个错误。更好地解决上述问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多