这是我所做的样本考试的问题。
给出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]
答案 0 :(得分:3)
这是一个相对简单的递归:
split_into_pairs([], []).
split_into_pairs([First, Second | Tail], [[First, Second] | Rest]) :-
split_into_pairs(Tail, Rest).
第一条规则说空列表已经拆分成对;第二个要求源列表至少有两个项目,将它们配对,并插入配对尾部列表的结果。
您的解决方案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).