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])
我是 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])