这似乎是一个奇怪的问题,可以由findall/3
谓词简单地回答。但是我的问题比这更深一点。
所以我有一个名为ran_num/1
的谓词,它返回五个随机数中的一个(我不知道这些数字是什么,但只有5个)。
当我运行谓词时,它返回此输出作为示例:
?- ran_num(X).
X = 2
?-
请注意,没有替代答案,按;
将无效。 Prolog正在等待另一个查询命令。
如果我对此运行findall,结果为:
?- findall(X, ran_num(X), L).
L = [2]
?-
是否有我可以实现的内置谓词或方法,它将为我提供可生成的所有可能数字?例如,我可以得到一个[2,60,349,400,401]的列表。
假设我无法更改ran_num/1
谓词以给我替代。
答案 0 :(得分:1)
您面临的问题是ran_num/1
就解释器而言是确定性的。它不知道再次调用它可能会产生不同的结果。
Prolog的random_between/3
就是这样的,所以我已经按如下方式定义了谓词ran_num/1
。
ran_num(X) :-
random_between(1, 5, Y),
ran_num_mapping(Y, X).
ran_num_mapping(1, 2).
ran_num_mapping(2, 60).
ran_num_mapping(3, 349).
ran_num_mapping(4, 400).
ran_num_mapping(5, 401).
这是确定性的,就像你的例子一样。
因此ran_num/1
会随机返回五个不同数字中的一个,我们想知道这五个数字。这意味着我们需要继续调用ran_num/1
,直到我们有一组五个数字。
我们可以定义一个长度为S
的{{1}}集。
N
如果我们有一组长度为5的话,那么我们就拥有了所有“ran_num”。
is_set_of_length(S, N) :-
is_set(S),
length(S, N).
否则,我们得到另一个ran_num,将其添加到集合中,然后再次检查。
get_all_ran_nums(Y, Y) :-
is_set_of_length(Y, 5), !.
我们需要以空列表开始。
get_all_ran_nums(L, T) :-
ran_num(X),
ord_add_element(T, X, Lout),
get_all_ran_nums(L, Lout).
这会产生我们的结果。
get_all_ran_nums(X) :-
get_all_ran_nums(X, []).
请注意,?-
get_all_ran_nums(X).
X = [2, 60, 349, 400, 401]
?-
的第一个条款中的剪切是必要的,否则我们可以保持回溯但获得相同的结果。因为我们可以继续生成ran_nums并将它们添加到集合中;如果他们已经 in 该集合,get_all_ran_nums/2
仍然会成功。
另请注意,由于数字是随机生成的,理论上 ,这可能会持续运行任何时间长度而不会得到我们需要停止的第五个数字。