我正在处理一个更长的问题,我在列表表单中复制了N次元素,我相信使用append是正确的方法。这个小谓词理论上应该是这样的:
?- repl(x,5,L).
L = [x, x, x, x, x] ;
false.
我似乎无法在网上找到任何提示,复制单个元素,但我相信我们需要使用append,但没有递归解决方案。我来自更多的Haskell背景,这个问题会更容易执行。有人可以帮我开始吗? :)
到目前为止:
repl(E, N, R) :-
N > 0, append([E], [], R), writeln(R), repl(E, N-1, R), fail.
这给了我:
?- repl(x,5,L).
[x]
[x]
[x]
[x]
[x]
false.
关闭但不完全!
答案 0 :(得分:11)
递归方法是直截了当的,可行。我建议把它搞清楚。但这是一个有趣的选择:
repl(X, N, L) :-
length(L, N),
maplist(=(X), L).
如果N
被实例化,那么length(L, N)
将生成一个长度为N
的列表,其中只有"空白" (不要关心条款)。然后,maplist(=(X), L)
会将L
的每个元素与变量X
统一起来。
这给出了一个很好的关系方法,并在一般情况下产生了明智的结果:
| ?- repl(X, N, L).
L = []
N = 0 ? ;
L = [X]
N = 1 ? ;
L = [X,X]
N = 2 ? ;
| ?- repl(X, N, [x,x,x]).
N = 3
X = x
yes
...
要想出一个递归的情况,请考虑你的基本情况是什么样的(repl
计数为0
- 那么列表是什么样的呢?)。在递归的情况下,请考虑:
repl(X, N, [X|T]) :- ...
含义:如果...... ,则列表[X|T]
是重复X
次的元素N
。弄清楚如果是什么?如果你的基本情况是0
长度,那么你的递归可能会描述长度为repl
的{{1}}列表N
长度为repl
的列表的N-1
。不要忘记这个递归规则,以确保N > 0
避免回溯无限递归。如果你不需要谓词是纯粹的关系,并假设N
被实例化,那么它可以相当简单。
如果你制作一个简单的递归版本,你可以"包装"它在这个谓词中使它适用于变量N
:
repl(X, N, L) :-
length(L, N),
simple_recursive_repl(X, N, L).
...
因为length/2
是关系型的,所以它比仅提供给定列表的长度更有用。当N
和L
未实例化时,它将成为变量列表的生成器,从0
开始。在Prolog提示符下键入length(L, N).
,看看会发生什么。
答案 1 :(得分:3)
您给出了您想象的谓词的以下示例:
?- 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).
请注意,如果重复次数为负,则会抛出域错误。这使用SWI-Prolog中的库error
。如果您的Prolog不支持此功能,那么您可以退出最后一个条款。
你不知道如何在Prolog中解决这个问题的声明和你在Haskell中解决这个问题的说法的组合对我来说似乎有点奇怪。我想你只能比较两种实现的难度,只能比较两种实现的难度。
答案 2 :(得分:1)