Prolog:迭代列表并创建谓词

时间:2016-11-29 07:47:46

标签: prolog

我创建了一个谓词enum,它带有一个列表和一个数字,例如[1,2,3,4]3,并返回一个包含长度为3的列表的列表。清单介绍。所以在给定enum([1,2,3,4],3,[[1,2,3],[2,3,4]])的示例中。 我创建了一个只接受长度为N的第一个列表的函数,但是当我尝试将其循环以获取所有其他列表时,我会收到错误。谢谢你的帮助。

append([],L,L).
append([H|T],L2,[H|L3]):- append(T,L2,L3).

len([],0).
len([_|B],X):- len(B,X1), X is X1+1.

take(_,X,Y) :- X =< 0, !, X =:= 0, Y = [].
take([],_,[]).
take([A|B],X,[A|C]):- Z is X-1, take(B,Z,C).

enum([],_,[]).
enum([N1|N2],N3,N4):-
   len([N1|N2],U),
   N3=<U,
   take([N1|N2],N3,T1),
   append([N4],[T1],T2),
   !,
   enum(N2,N3,T2).

2 个答案:

答案 0 :(得分:0)

我将专注于take/3谓词,这是你问题的核心。为了获得[2,3,4] [1,2,3,4]之类的子列表,您必须能够跳过第一个元素,并获取其余元素的子列表。

您可以通过在您的定义中添加此子句来实现此目的:

take([_|Xs], N, Ys) :- take(Xs, N, Ys).

有了这个,您现在可以获得长度为3的几个不同的子列表,还有一些其他多余的解决方案:

?- take([1,2,3,4], 3, Xs).
Xs = [1, 2, 3] ;
Xs = [1, 2, 4] ;
Xs = [1, 2] ;
Xs = [1, 3, 4] ;
Xs = [1, 3] ;
Xs = [1, 4] ;
Xs = [1]  % etc.

这是因为您的子句take([], _, [])接受一个空列表作为任何长度的&#34;子列表&#34;一个空列表。我想你只想接受空列表作为长度为0的子列表。如果你删除这个子句,你的第一个子句将强制执行,你只得到长度恰好为3的解决方案:

?- take([1,2,3,4], 3, Xs).
Xs = [1, 2, 3] ;
Xs = [1, 2, 4] ;
Xs = [1, 3, 4] ;
Xs = [2, 3, 4] ;
false.

作为附注,你的第一个条款没有问题,但它可以简化为:

take(_,X,Y) :- X = 0, !, Y = [].

我还建议您使用更易读的变量名称。对于列表长度等数字,我们经常使用N。对于列表,通常会将XsYs等名称与XY等一起用于相应列表的成员。

最后,要查找谓词的所有解法,您需要使用系统谓词,如setofbagoffindall。无法在纯Prolog中编写enum

答案 1 :(得分:0)

因为我不确定其他答案中的建议,所以这是我对你的问题的看法。

首先,不要定义自己的append/3length/2append/3现在是Prolog民间传说,您可以在textbooks 30 years old找到它。 length/2很难自行解决,使用内置功能。<​​/ p>

现在:要获取列表N前面的第一个L元素,您可以说:

length(Front, N),
append(Front, _, L)

您可以创建所需长度的列表,然后使用append/3从您的列表中拆分前面。

考虑到这一点,定义谓词sliding_window/3

就足够了
sliding_window(L, N, [L]) :-
        length(L, N).
sliding_window(L, N, [W|Ws]) :-
        W = [_|_], % W should be at least one long
        length(W, N),
        append(W, _, L),
        L = [_|L0],
        sliding_window(L0, N, Ws).

这种作品,但在给你所有有用的答案之后它会循环:

?- sliding_window([a,b], N, Ws).
N = 2,
Ws = [[a, b]] ;
N = 1,
Ws = [[a], [b]] ;
% loops

它因为相同的小片段而循环:

length(Front, N),
append(Front, _, L)

使用length/2,您可以继续生成长度增加的列表;一旦Front超过Lappend/3将失败,length/2会生成更长的列表,依此类推。

其中一种方法是使用between/3来约束前线的长度。如果你把它放在自己的谓词中:

front_n(L, N, F) :-
        length(L, Max),
        between(1, Max, N),
        length(F, N),
        append(F, _, L).

有了这个:

sliding_window(L, N, [L]) :-
        length(L, N).
sliding_window(L, N, [W|Ws]) :-
        front_n(L, N, W),
        L = [_|L0],
        sliding_window(L0, N, Ws).

现在它终于奏效了:

?- sliding_window([a,b,c,d], 3, Ws).
Ws = [[a, b, c], [b, c, d]] ;
false.

?- sliding_window([a,b,c], N, Ws).
N = 3,
Ws = [[a, b, c]] ;
N = 1,
Ws = [[a], [b], [c]] ;
N = 2,
Ws = [[a, b], [b, c]] ;
false.

练习:摆脱无害但不必要的选择点。