决定论
您给出了您设想的谓词的以下示例:
?- repl(x,5,L).
L = [x, x, x, x, x] ;
false.
请注意,;
这里的生产力不是很高。如果你想重复x
5 次,那么这可以通过一种方式完成。因此,我会将这个谓词指定为确定性而非非确定性,就像您所做的那样。
重复列表
尽管输出在精神上看起来与设想的结果非常接近,但您的代码实际上与可行的解决方案相去甚远。您尝试同时定义基本情况和递归情况,这是行不通的。
这是基本和递归案例的简单实现(但没有@lurker 给出的有趣:-)):
repeating_list(_, 0, []):- !.
repeating_list(H, Reps1, [H|T]):-
Reps2 is Reps1 - 1,
repeating_list(H, Reps2, T).
从某种意义上说,@lurker 的实现更简单,而且肯定更短。
一些扩展
在实际/生产代码中,您希望捕获类型错误并使用相同的谓词处理不同的实例化。第二个子句检查给定列表是否由重复元素组成(如果是,则存在哪一个以及出现了多少次)。
%! repeating_list(+Term:term, +Repeats:integer, -List:list(term)) is det.
%! repeating_list(?Term:term, ?Repeats:integer, +List:list(term)) is det.
repeating_list(_, 0, []):- !.
% The term and number of repetitions are known given the list.
repeating_list(H, Reps, L):-
nonvar(L), !,
L = [H|T],
forall(
member(X, T),
% ==/2, since `[a,X]` does not contain 2 repetitions of `a`.
X == H
),
length([H|T], Reps).
% Repetitions is given, then we generate the list.
repeating_list(H, Reps1, [H|T]):-
must_be(nonneg, Reps1), !,
Reps2 is Reps1 - 1,
repeating_list(H, Reps2, T).
% Repetitions is not `nonneg`.
repeating_list(_, Reps, _):-
domain_error(nonneg, Reps).
请注意,如果重复次数为负,我会抛出域错误。这使用error
SWI-Prolog 中的库。如果你的 Prolog 不支持这个特性,那么你可以省略最后一个子句。
PS:与 Haskell 的比较
你不知道如何在 Prolog 中解决这个问题的陈述和你在 Haskell 中更容易解决这个问题的陈述对我来说似乎有点奇怪。我认为只有了解了两种实现的外观后,才能比较它们的难度。