如何在Prolog中填充列表?

时间:2015-01-31 12:31:51

标签: prolog

假设您有以下谓词:

random_int(X/Y):-
  random(1,100,X),
  random(1,100,Y),
  X\=Y.

如何使用此谓词的结果填充大小为n的列表?

我尝试了以下代码,但只有在第一次尝试时random_int(X)为true时才会填充列表,即它不会回溯以尝试X和Y的其他组合。

findall(X,(between(1,N,_), random_int(X)),L).

4 个答案:

答案 0 :(得分:1)

您可以使用findall/3执行此操作:

random_list(N, L) :-
    findall(X, (between(1,N,_), random(50,100,X)), L).

另一种简洁的方法是:

random_list(N, L) :-
    length(L, N),
    maplist(random(50, 100), L).

结果是:

| ?- random_list(5, L).

L = [69,89,89,95,59]

yes
| ?-

一般情况下,如果您有一个谓词p(X1,X2,...,Xn,Y),并且要使用对Y的连续调用填充结果p/(n+1)的列表,则可以使用length(List, Length)设置列表的长度,然后maplist(p(X1,...,Xn), List)填充列表。或者,使用findall/3,您可以执行findall(X, (between(1,N,_), p(X1,...,Xn,X)), L).

<小时/> 编辑根据问题的更新条件,生成的列表为唯一值...

random谓词不是生成器,因此它们不会在回溯时创建新的随机数(无论是唯一的还是其他的)。因此,这个解决方案同样会生成一个满足要求的列表,然后成功而不会在回溯中产生更多这样的列表:

% Generate a random number X between A and B which is not in L

rand_not_in(A, B, L, X) :-
    random(A, B, X1),
    (   memberchk(X1, L)
    ->  rand_not_in(A, B, L, X)
    ;   X = X1
    ).

% Generate a list L of length N consisting of unique random numbers
%    between A and B

random_list(N, L) :-
    random_list(N, 50, 100, [], L).
random_list(N, A, B, Acc, L) :-
    N > 0,
    rand_not_in(A, B, A, X),
    N1 is N - 1,
    random_list(N1, A, B, [X|A], L).
random_list(0, _, _, L, L).

另一种方法,在SWI Prolog中,您可以使用randseq,它会在1N的范围内提供随机序列。只需缩放它:

random_list(N, A, B, L) :-
    A < B,
    Count is B - A + 1,
    randseq(N, Count, L1),
    Offset is A - 1,
    maplist(offset(Offset), L1, L).

offset(X, Offset, Y) :-
    Y is X + Offset.

?- random_list(5, 50, 100, L).
L = [54, 91, 90, 78, 75].

?-

答案 1 :(得分:1)

我发现这个小应用程序&#39; clpfd有趣:

?- N=10,M=12, repeat, findall(X, (between(1,N,_),random(1,M,X)), L), clpfd:all_different(L).
N = 10,
M = 12,
L = [5, 4, 6, 7, 9, 11, 2, 3, 8|...] 
.

注意:M 必须是&gt; Ñ

答案 2 :(得分:1)

我想一个简单的方法是制作一个1:100的列表,并从中抽取100次大小为2的样本,无需替换。由于这是Prolog而不是R,你可以改为:

:- use_module(library(lists)).
:- use_module(library(random)).

random_pairs(Pairs) :-
    findall(X/Y,
        (   between(1, 100, _),
            randseq(2, 100, [X,Y])
        ), R).

这至少在SWI-Prolog中可用,但它是免费软件,网站上提供了randseq/3的来源。

除非严格必要,否则最好不要使用findall,最好写一下:

random_pairs(Pairs) :-
    length(Pairs, 100),
    maplist(randseq(2, 100), Pairs).

或者,如果X/Y很重要,

random_pairs(Pairs) :-
    length(Pairs, 100),
    maplist(rand_couple(100), Pairs).

rand_couple(N, X/Y) :-
    randseq(2, N, [X,Y]).

TL; DR 使用可用的库

答案 3 :(得分:0)

 random_len([],0).
 random_len([Q|T],N)  :-
    random(1,100,Q), 
    random_len(T,X), 
    N  is  X+1.