Prolog - 理解递归谓词返回列表

Prolog - understanding recursive predicate returning list

我是 Prolog 的新手,想知道是否可以帮助我更好地理解下面的代码。我理解与 'divides' 和 'find_num' 相关的代码,但我很难理解 'check_list' 发生的事情。如果能帮助我加深理解,我们将不胜感激。

 divides(X, Y) :-
     X mod Y =:= 0.

 find_num(X, Y, Lout) :-
      findall(N, between(1, X, N), Lin),
      check_list(Lin, Y, Lout).

 check_list([], _, []).

 check_list([H | Tin], Y, [H | Tout]) :-
   divides(H, Y),
   check_list(Tin, Y, Tout).

 check_list([H | Tin], Y, Lout) :-
   \+ divides(H, Y),
   check_list(Tin, Y, Lout).

让我们看一个更简单的谓词:

copy_list([],[]).
copy_list([H|Tin],[H|Tout]) :- copy_list(Tin,Tout).

如果您传入两个相同的列表,那么如果它们相等,则此谓词将成功。如果您传递一个列表和一个变量,无论哪种方式,都会复制列表。

按照惯例,输入在左边,输出在右边。

让我们看看这个查询:

?- copy_list([1,2,3],Xs).

内部 Prolog(在我的例子中是 SWI)用内部名称替换变量 Xs,因此第一次调用是 copy_list([1, 2, 3], _52812)。 Prolog 查找谓词匹配并找到 copy_list([H|Tin],[H|Tout])。然后它统一并得到 copy_list([1|2,3],[1|_55684])。然后它试图证明 body.

它的第二次调用是copy_list([2,3],_55684)。 Prolog 查找谓词匹配并找到 copy_list([H|Tin],[H|Tout])。然后它统一并得到 copy_list([2|3],[2|_69116])。然后它试图证明 body.

它的第三次调用是copy_list([3],_69116)。 Prolog 查找谓词匹配并找到 copy_list([H|Tin],[H|Tout])。然后它统一并得到 copy_list([3|[]],[3|_69734])。然后它试图证明 body.

空列表谓词 copy_list([],[]). 在第四次调用时现在匹配。所以它开始展开递归。它将 _69734 与空列表统一起来。它统一了 _69116[3],然后 _55684[2,3],最后 _52812[1,2,3],并宣告成功。程序是真的。

简而言之,它是这样做的:

copy_list([1, 2, 3], _52812)
copy_list([2, 3], _55684)
copy_list([3], _69116)
copy_list([], _69734)
copy_list([], [])
copy_list([3], [3])
copy_list([2, 3], [2, 3])
copy_list([1, 2, 3], [1, 2, 3])