我正在研究一个更长的问题,我在列表表单中复制了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.

关闭但不完全!

===============>>#1 票数: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]是重复N次的元素X 弄清楚是什么? 如果你的基本情况是长度为0 ,那么你的递归很可能将描述repl的长度列表N的方面repl的长列表的N-1 不要忘记在这个递归规则中确保N > 0以避免回溯无限递归。 如果你不需要谓词纯粹是关系的,并假设N被实例化,那么它可以相当简单。

如果你创建一个简单的递归版本,你可以将它“包装”在这个谓词中,使其适用于变量N

repl(X, N, L) :-
    length(L, N),
    simple_recursive_repl(X, N, L).

...

因为length/2是关系的,所以它比仅提供给定列表的长度更有用。 NL未实例化时,它将成为变量列表的生成器,从长度0开始。 类型, length(L, N). 在Prolog提示下,看看会发生什么。

===============>>#2 票数: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不支持此功能,那么您可以退出最后一个条款。

PS:与Haskell的比较

您不知道如何在Prolog中解决此问题的声明与您在Haskell中更容易解决此问题的声明的组合对我来说似乎有点奇怪。 我想你一旦知道它们两者的外观,就只能比较两种实现的难度。

===============>>#3 票数:1

我更喜欢使用findall / 3来构建列表, / 3 之间使用范围:

repl(E, N, L) :- findall(E, between(1, N, _), L).

  ask by user3290526 translate from so

未解决问题?本站智能推荐: