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

Recursion 如何编写Prolog谓词将列表拆分为成对元素的列表?,recursion,prolog,Recursion,Prolog,这是我做的一次抽样考试中的一个问题 给出Prolog谓词的定义,将_拆分为_对,以列表作为参数,并作为结果返回由成对元素组成的列表。例如,split_为_对([1,2,3,4,5,6],X)将返回结果X=[[1,2],[3,4],[5,6]。类似地,split_为_对([a,2,3,4,a,a,a,a],X)将返回结果X=[[a,2],[3,4],[a,a],[a,a]而split_为_对([1,2,3],X)将返回否 我相信这并不意味着要使用内置谓词来完成,但也不需要太复杂,因为它只值8/12

这是我做的一次抽样考试中的一个问题

给出Prolog谓词的定义,将_拆分为_对,以列表作为参数,并作为结果返回由成对元素组成的列表。例如,
split_为_对([1,2,3,4,5,6],X)
将返回结果
X=[[1,2],[3,4],[5,6]
。类似地,
split_为_对([a,2,3,4,a,a,a,a],X)
将返回结果
X=[[a,2],[3,4],[a,a],[a,a]
split_为_对([1,2,3],X)
将返回

我相信这并不意味着要使用内置谓词来完成,但也不需要太复杂,因为它只值8/120分

我不确定它应该为两个元素的列表做什么,所以我猜要么不指定,这样它就会返回no,要么
将\u拆分为\u对([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]

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

split_into_pairs([], []).
split_into_pairs([First, Second | Tail], [[First, Second] | Rest]) :-
    split_into_pairs(Tail, Rest).
第一条规则说一个空列表已经被分成对;第二种方法要求源列表至少有两个项,将它们配对,并在它们后面插入尾列表配对的结果

这是一本书

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

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

注意,此解决方案不考虑空列表的成对列表,因此<代码> SPLITY-ITO对([],x)< /C>会失败。

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

将_拆分为_对([A,B],
[
]
>)
>:-

split_为_对([A,B|T],X):-split_为_对(T,XX),

X
=

现在它是正确的:
=
被用来代替
is
(通常与算术运算一起使用),两个子句都正确地以点结尾,第一个子句中添加了一个割,以使谓词具有确定性,从而只产生一个结果。正确的结构是通过用括号将每对元素包含在它们自己的列表中而产生的

但这是低效的,因为它描述了一个递归过程——它在从基本情况返回的过程中构建结果

有效的定义在前进的道路上起作用
,从一开始就是:

split_into_pairs([A,B],[[A,B]]):- !.
split_into_pairs([A,B|T], X) :- X = [[A,B]|XX], split_into_pairs(T, XX).
这就是尾部递归模cons优化技术的本质,它将递归过程转化为迭代过程,从而能够在恒定的堆栈空间中运行。它与累加器技术的尾部递归非常相似

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

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

好吧,看起来我确实尝试过这样做,但是我误解了尾巴是如何工作的,我认为这是不对的。谢谢你的帮助,现在说得通了。