在Prolog中轮流迭代列表元素

3
我有一个需要构造的谓词 repeat/3。它应该将列表中的所有元素重复 n 次。例如:
?- repeat([a,b,a,a,c],2,X).

会产生以下结果: X = [a,a,b,b,a,a,a,a,c,c]。
我为此编写的当前代码如下:
repeat([],_,[]).
repeat(_,0,[]).
repeat([A],Int,[A|X]):- Int1 is Int-1, repeat([A],Int1,X).
repeat(A,1,A).
repeat([A|Tail],Int,[A|X]):- Int1 is Int-1, repeat([A|Tail],Int1,X).

它将返回:
1)当给出一个空列表时,返回一个空列表。
2)当给出数字0作为参数时,返回一个空列表。
3)一封信n次。
4)给定的列表一次。
现在,我遇到的问题是代码的最后一行。
5)目前这行代码会将第一个元素重复n次后,返回列表中的所有元素。
示例:
?- repeat([a,b,b,c],3,X).
X = [a, a, a, b, b, c]  

我觉得解决方案是我要遍历列表,对于每个元素重复n次,但我不知道该怎么做。
我尝试过的一个想法是,在传递给谓词的数字达到1时将其转换回原始数字,然后使用尾部继续谓词:
repeat([],_,[]).
repeat(_,0,[]).
repeat([A],Int,[A|X]):- Int1 is Int-1, repeat([A],Int1,X).
repeat([A|Tail],1,[A|X]):- repeat(Tail,Int,X).  % The line where I made a change.
repeat([A|Tail],Int,[A|X]):- Int1 is Int-1, repeat([A|Tail],Int1,X).

这没有成功。我现在不知道我是否在正确的轨道上。任何帮助都将不胜感激。

1
它重复第一个元素N次,接下来的项目只重复一次。这是因为您会递减N直到达到零。但是,此时不再有关于原始N的信息。 - Willem Van Onsem
我会移除 [A] 这些情况;你不需要它们,它们是不必要的边缘情况。[A|Tail][a] 统一绑定 A=a, Tail=[]。此外,我建议使用 succ(Int1, Int) 而不是 Int1 is Int-1,因为它可以双向成功。 - Daniel Lyons
那么,解决方案是将原始N传递给尾谓词吗?还是我理解有误? - T44v1
@T44v1:不,你需要访问原始的 N 和一个你要递减的 N。从递减计数器达到零的那一刻起,你就可以继续处理源列表中的下一个元素,并使用你传递的 N 重置该计数器。 - Willem Van Onsem
1个回答

2
尽管还有其他问题,但最重要的问题是你需要将N递减直到达到零以重复第一个元素。但是一旦它达到零,你就不能再获得原始的N了。
那么我们如何存储原始的N呢?我们可以简单地引入一个新的谓词repeat/4,具有以下特点:
repeat(L, N, LN) :-
    repeat(L, N, N, LN).

所以我们通过复制N将repeat/3重定向到repeat/4。这个想法是只减少一个参数。从那个参数变为零的那一刻起,我们将“重置”该参数,通过从第二个不递减的N中获取该值。
所以现在我们只需要解决repeat/4的问题。如果我们到达列表的末尾,则无论N的值如何,重复都是一个空列表。
repeat([], _, _, []).

如果第一个N已经减为零,我们就继续处理列表的下一个元素,并将该N重置为初始值:

repeat([_|T], 0, N, LN) :-
    repeat(T, N, N, LN).

最后,如果我们还没有达到零,我们当然会在结果前加上第一个列表的头部:

repeat([H|T], A, N, [H|LN]) :-
    A > 0,
    A1 is A-1,
    repeat([H|T], A1, N, LN).

如果我们把所有东西放在一起,我们就得到了:
repeat(L, N, LN) :-
    repeat(L, N, N, LN).

repeat([], _, _, []).
repeat([_|T], 0, N, LN) :-
    repeat(T, N, N, LN).
repeat([H|T], A, N, [H|LN]) :-
    A > 0,
    A1 is A-1,
    repeat([H|T], A1, N, LN).

1
好的,非常感谢你的帮助!我已经为这个任务苦思冥想了几个小时。 - T44v1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接