如何编写Prolog谓词将列表拆分为配对元素列表?

时间:2013-06-14 15:40:09

标签: recursion prolog

这是我所做的样本考试的问题。

给出Prolog谓词split_into_pairs的定义,该谓词将列表作为参数,并返回由成对元素组成的列表。例如,split_into_pairs([1,2,3,4,5,6],X)将返回X=[[1,2],[3,4],[5,6]]。同样,split_into_pairs([a,2,3,4,a,a,a,a],X)将返回结果X=[[a,2],[3,4],[a,a],[a,a]],而split_into_pairs([1,2,3],X)将返回No

我认为不应该使用内置谓词来完成,但它不应该太复杂,因为它只值8/120标记。

我不确定它应该对两个元素的列表做什么,所以我想这可能没有指定,所以它返回no,或split_into_pairs([A,B],[[A,B]])

我的主要问题是如何正确地进行递归调用,没有额外的括号,最终不会像X=[[A,B],[[C,D],[[E,F]]]]那样?

我最近的尝试是以下代码的变体,但显然这是不正确的。

split_into_pairs([A,B],[A,B])
split_into_pairs([A,B|T], X) :- split_into_pairs(T, XX), X is [A,B|XX]

2 个答案:

答案 0 :(得分:3)

这是一个相对简单的递归:

split_into_pairs([], []).
split_into_pairs([First, Second | Tail], [[First, Second] | Rest]) :-
    split_into_pairs(Tail, Rest).

第一条规则说空列表已经拆分成对;第二个要求源列表至少有两个项目,将它们配对,并插入配对尾部列表的结果。

这是demo on ideone

您的解决方案could be fixed as well在结果中添加方括号,并将规则的第二部分移到标题中,如下所示:

split_into_pairs([A,B],[[A,B]]).
split_into_pairs([A,B|T], [[A,B]|XX]) :- split_into_pairs(T, XX).

请注意,此解决方案不会将空列表视为对列表,因此split_into_pairs([], X)会失败。

答案 1 :(得分:0)

您的代码几乎正确无误。它有明显的语法问题和几个实质性问题:

split_into_pairs([A,B], [ [ A,B ] ] ) :- !.

split_into_pairs([A,B|T], X) :- split_into_pairs(T, XX),

X = [ [ A,B ] | XX ] .

现在它是正确的:=代替is(通常与算术操作一起使用),两个子句都被点正确终止,第一个一个人加入了一个剪切,使谓词确定性,只产生一个结果。通过将每对元素用括号括起来,生成正确的结构。

这样效率很低,因为它描述了一个 递归过程 - 它在回来的路上构建结果 从基础案例。

高效的定义在前进的道路上

split_into_pairs([A,B],[[A,B]]):- !.
split_into_pairs([A,B|T], X) :- X = [[A,B]|XX], split_into_pairs(T, XX).

这是尾递归模数缺点优化技术的本质,它将递归过程转换为 迭代 - 这样才能运行在恒定的堆栈空间中。它与使用累加器技术的尾递归非常相似。

必须引入剪辑,因为这两个条款不是相互排斥的:如果[A,B] [A,B|T],则与T=[]统一的术语也可以统一。我们可以通过使两个条款相互排斥来摆脱削减:

split_into_pairs([], [] ).
split_into_pairs([A,B|T], [[A,B]|XX]):- split_into_pairs(T, XX).