Recursion Prolog-flatte/2实现

Recursion Prolog-flatte/2实现,recursion,prolog,infinite-recursion,Recursion,Prolog,Infinite Recursion,下面是我的展平/2实现: flt([], []). flt([H|L], [H|X]):- not(is_list(H)), flt(L, X). flt([H|L], X):- append(R, F, X), flt(H, R), flt(L, F). 预期结果如下: ?- flt([1,[2,3,[4,5],6],7], X). X = [1, 2, 3, 4, 5, 6, 7] 然而,当我点击超出堆栈限制。为什么会发生这种情况?无限递归在哪里?

下面是我的
展平/2
实现:

flt([], []).
flt([H|L], [H|X]):-
    not(is_list(H)),
    flt(L, X).
flt([H|L], X):-
    append(R, F, X),
    flt(H, R),
    flt(L, F).
预期结果如下:

?- flt([1,[2,3,[4,5],6],7], X).
X = [1, 2, 3, 4, 5, 6, 7]
然而,当我点击
超出堆栈限制。为什么会发生这种情况?无限递归在哪里?


谢谢。

问题是您只使用未实例化的变量调用
append(R,F,X)

对于
flt(+List,-Flatlist)
,只有一种解决方案。然而,在回溯时,
append(R,F,X)
会一次又一次地尝试,但从未找到其他解决方案

您可以通过询问来测试这一点

?- append(R, F, X).
R = [],
F = X ;
R = [_948],
X = [_948|F] ;
R = [_948, _960],
X = [_948, _960|F] ;
R = [_948, _960, _972],
X = [_948, _960, _972|F] ;
R = [_948, _960, _972, _984],
X = [_948, _960, _972, _984|F] ;
R = [_948, _960, _972, _984, _996],
X = [_948, _960, _972, _984, _996|F] 
...
解决方案是重新安排第三条中的目标:

flt([H|L], X):-
    flt(H, R),
    flt(L, F),
    append(R, F, X).
这是一个很好的例子,说明Prolog不是纯粹的声明性的,因为它通过简单的时间顺序回溯实现解析,将过程特性强加于语言


为了说明这个问题,请看一下这个跟踪(为了强调循环问题,我跳过了很多次):

这张图用图形显示了它。询问其他答案后发生的情况为红色


另一种可能的解决方案是增加切割:

flt([], []).
flt([H|L], [H|X]):-
    not(is_list(H)),
    flt(L, X),
    !.

flt([H|L], X):-
    append(R, F, X),
    flt(H, R),
    !,
    flt(L, F).
flt([], []).
flt([H|L], [H|X]):-
    not(is_list(H)),
    flt(L, X),
    !.

flt([H|L], X):-
    append(R, F, X),
    flt(H, R),
    !,
    flt(L, F).