如何编写一个prolog程序,将List1和List2作为输入,得到的列表是List1和List2的交替元素?

如何编写一个prolog程序,将List1和List2作为输入,得到的列表是List1和List2的交替元素?,list,recursion,prolog,artificial-intelligence,List,Recursion,Prolog,Artificial Intelligence,这是我第一次尝试在一个非示例程序上使用递归,因为我缺乏经验 预期的有效查询: mixElements([],[a,b,c], [a,b,c]). mixElements([a,b],[],[a,b]). mixElements([a,b,c],[d,e,f],[a,d,b,e,c,f]). mixElements([a,b,c],[d,e,f,g,h],[a,d,b,e,c,f,g,h]). 在这里,我试图创建一个基本情况,当输入列表为空时,只返回结果 /* Base cases */ mix

这是我第一次尝试在一个非示例程序上使用递归,因为我缺乏经验

预期的有效查询:

mixElements([],[a,b,c], [a,b,c]).
mixElements([a,b],[],[a,b]).
mixElements([a,b,c],[d,e,f],[a,d,b,e,c,f]).
mixElements([a,b,c],[d,e,f,g,h],[a,d,b,e,c,f,g,h]).
在这里,我试图创建一个基本情况,当输入列表为空时,只返回结果

/* Base cases */
mixElements([],[],Result).
递归语句的逻辑是输入列表必须至少包含1个或多个元素。因此,对于列表1和列表2,它们必须分别用[H | L]表示。然后将H1和H2附加到结果中,以创建列表元素的交替模式。最后,它将使用列表的其余部分L1和L2调用mixElements,结果列表现在应该包含两个列表的第一个头元素

/* Recursive case where both L1 and L2 are not empty */
mixElements([H1|L1],[H2|L2],Result) :- append(H1,H2,Result), mixElements(L1,L2,Result).

我的结果总是“否”。

这里基本上有四种情况:

  • 第一个列表为空,第二个列表为空,在这种情况下,结果应为空:

    mixElements([],[],[]).
    
  • 第一个列表为空,第二个列表为非空,在这种情况下,结果为第二个列表:

    mixElements([],[H2|T2],[H2|T2]).
    
  • 第一个列表为非空,第二个列表为空,在这种情况下,结果为第一个列表:

    mixElements([H1|T1],[],[H1|T1]).
    
  • 最后两个列表都是非空的,在这种情况下,结果的前两个元素是列表的开头,然后是混合列表的结尾:

    mixElements([H1|T1],[H2|T2],[H1,H2|TT]) :-
        mixElements(T1,T2,TT).
    
  • 现在,我们可以将所有这些放在一起:

    mixElements([],[],[]).
    mixElements([],[H2|T2],[H2|T2]).
    mixElements([H1|T1],[],[H1|T1]).
    mixElements([H1|T1],[H2|T2],[H1,H2|TT]) :-
        mixElements(T1,T2,TT).
    
    现在我们创建了一些多余的语句。例如,我们可以将前两条语句合并为一条,如:

    mixElements([],L,L).
    mixElements([H1|T1],[],[H1|T1]).
    mixElements([H1|T1],[H2|T2],[H1,H2|TT]) :-
        mixElements(T1,T2,TT).
    

    我把它留作进一步改进谓词的练习。例如,您可以使用切割,但这可以消除谓词的多方向性,这有时非常有用。

    在处理列表时,通常值得考虑DCG,因为它们生成易于阅读的代码。它进一步帮助读者为关系选择一个描述性名称,比如list\u list\u interlocked/3。考虑下面的代码:

    list_list_interlocked(L1,L2,I) :-
       phrase(interlocked(L1,L2),I).
    
    interlocked([],[]) -->           % if both input lists are empty
       [].                           % the resulting list is also empty
    interlocked([],[H2|T2]) -->      % if the first input list is empty
       [H2],                         % the head of the second is in the list
       interlocked([],T2).           % the relation holds for the tail as well
    interlocked([H1|T1],[]) -->      % if the second input list is empty
       [H1],                         % the head of the first is in the list
       interlocked(T1,[]).           % the relation holds for the tail as well
    interlocked([H1|T1],[H2|T2]) --> % if both lists are non-empty
       [H1,H2],                      % the heads are in the list
       interlocked(T1,T2).           % the relation holds for the tails as well
    
    您的示例查询将生成所需的结果:

       ?- list_list_interlocked([],[a,b,c],I).
    I = [a,b,c]
       ?- list_list_interlocked([a,b],[],I).
    I = [a,b]
       ?- list_list_interlocked([a,b,c],[d,e,f],I).
    I = [a,d,b,e,c,f]
       ?- list_list_interlocked([a,b,c],[d,e,f,g,h],I).
    I = [a,d,b,e,c,f,g,h]
    

    在不需要的地方使用append/3。当模式由至少一个元素的两个列表组成时,可以立即获得结果,然后递归处理尾部:

    mixElements([H1|L1],[H2|L2],[H1,H2|Rest]) :-
        !, mixElements(L1,L2,Rest).
    mixElements(L1,L2,Rest) :- append(L1,L2,Rest).
    

    提示:
    append/3
    需要什么类型的元素?@Will:有一个完美的副本!对于
    mixements(a,B,[a,B])
    a=[a,B],B=[]
    a=[],B=[a,B]
    来说,这不是一个潜在的问题吗?