Prolog

时间:2018-04-29 17:14:51

标签: prolog

如何在Prolog中编写递归定义以按以下方式创建交替列表:

如果通过获取列表alternate(K, L, M)

M成立 元素交替来自列表KL,例如:

?- alternate([1,2,3,4,5,6],[a,b,c],Zs).

Zs = [1, a, 2, b, 3, c, 4, 5, 6]

另外,如果一个列表比另一个列表长,那么剩下的元素 较长列表的结果显示在结果的末尾M

我对此问题的尝试如下,但它无效:

alternate([],L,L).
alternate(K, [], K).
alternate([Firstk|Restk], [Firstl|Restl], M):-
   K is [Firstk|Restk], L is [Firstl|Restl],
   M is [M|[Firstk]], K is Restk,
   M is [M|[Firstl]], L is Restl,
   alternate(K, L, M).

任何提示或建议赞赏

3 个答案:

答案 0 :(得分:4)

您可以通过在递归调用中翻转前两个参数来描述这种关系,如@WillNess在评论中所建议的那样。并且由于这两个列表的长度可能不同,因此有一个谓词一般描述列表以避免匹配非递归规则中的任意项会很有帮助。拥有一个更具描述性的名称来反映谓词的关系性质也是一件好事。考虑到所有这些,谓词可能看起来像这样:

islist([]).
islist([_|T]) :-
   islist(T).

list_list_interlocked([],L,L) :-
   islist(L).
list_list_interlocked([X|Xs],Ys,[X|Zs]) :-
   list_list_interlocked(Ys,Xs,Zs).

您的示例查询按预期工作:

?- list_list_interlocked([1,2,3,4,5,6],[a,b,c],Zs).
Zs = [1, a, 2, b, 3, c, 4, 5, 6].

如果第二个列表更长,则谓词也可以使用:

?- list_list_interlocked([1,2,3],[a,b,c,d,e,f],Zs).
Zs = [1, a, 2, b, 3, c, d, e, f].

它只适用于列表:

?- list_list_interlocked(definitelynolist,[],Zs).
false.

?- list_list_interlocked([],definitelynolist,Zs).
false.

后者是您需要islist/1的原因。如果您定义非递归规则,请执行以下操作:list_list_interlocked([],L,L).,然后Prolog可以将任意项与L统一,查询将产生错误的结果:

?- list_list_interlocked([],definitelynolist,Zs).
Zs = definitelynolist.

谓词也可用于其他方向,例如: 联锁时哪些列表会产生[1,a,2,b,3,c]

?- list_list_interlocked(X,Y,[1,a,2,b,3,c]).
X = [],
Y = [1, a, 2, b, 3, c] ;
X = [1, a, 2, b, 3, c],
Y = [] ;
X = [1],
Y = [a, 2, b, 3, c] ;
X = [1, 2, b, 3, c],
Y = [a] ;
X = [1, 2],
Y = [a, b, 3, c] ;
X = [1, 2, 3, c],
Y = [a, b] ;
X = [1, 2, 3],
Y = [a, b, c] ;
false.

答案 1 :(得分:1)

只需编写两个谓词,其中一个调用另一个,反之亦然,如下所示:

alternate1([],[],[]).
alternate1([],L,L).
alternate1([H|T],L,[H|T1]):-
    alternate2(T,L,T1).
alternate2([],[],[]).
alternate2(L,[],L).
alternate2(L,[H|T],[H|T1]):-
    alternate1(L,T,T1).

?- alternate1([1,2,3,4,5,6],[a,b,c],Zs).
Zs = [1, a, 2, b, 3, c, 4, 5, 6]
false

答案 2 :(得分:0)

我喜欢其他答案,尤其是@tas的答案。但是,这种方法仍然感觉到......"小步骤"。如果您正在处理两个列表并且应该从每个列表中选择元素,为什么不同时选择这两个元素而不是仅从一个元素中选择并交换列表?这感觉就像一个"算法",而不是关系的逻辑,声明性描述。

所以我提出以下建议:

alternate([], Ys, Ys).
alternate([X|Xs], [], [X|Xs]).
alternate([A | As], [B | Bs], [A, B | ABs]) :-
    alternate(As, Bs, ABs).

第三个子句涵盖了一般情况,交替使用两个非空列表:交替列表的前两个元素是要交替的两个列表的第一个元素。前两个条款只处理其中一个或另一个列表为空的情况。 (您可以将@ tas' islist目标添加到这些目标中,以强制另一个参数确实是正确的列表。)

以下是测试:

?- alternate([1,2,3,4,5,6],[a,b,c],Zs).
Zs = [1, a, 2, b, 3, c, 4, 5, 6] ;
false.

?- alternate([1,2,3],[a,b,c,d,e,f],Zs).
Zs = [1, a, 2, b, 3, c, d, e, f].

?- alternate(Xs, Ys, [1,a,2,b,3,c]).
Xs = [],
Ys = [1, a, 2, b, 3, c] ;
Xs = [1, a, 2, b, 3, c],
Ys = [] ;
Xs = [1],
Ys = [a, 2, b, 3, c] ;
Xs = [1, 2, b, 3, c],
Ys = [a] ;
Xs = [1, 2],
Ys = [a, b, 3, c] ;
Xs = [1, 2, 3, c],
Ys = [a, b] ;
Xs = [1, 2, 3],
Ys = [a, b, c] ;
false.

(在SWI-Prolog中,只对第一个参数进行索引,这会留下比某些替代选择更多的选择点。)