在这个问题Can be this lisp function be implemented recursively?上进行扩展,如果列表如下所示,是否可以在Prolog中包含所有组合:
items1(1, 2, 3).
items2(4, 5).
我可以通过以下数据格式得到答案:
items1(1).
items1(2).
items1(3).
items2(4).
items2(5).
?- findall((A,B), (items1(A), items2(B)), L).
L = [ (1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)].
我检查了来自http://www.swi-prolog.org/pldoc/man?predicate=permutation/2的排列谓词,但这是出于不同的目的。
答案 0 :(得分:1)
通过规范化数据库,您似乎已经很好地解决了问题。将列表[I_1, I_2, ..., I_n]
表示为事实items(I_1, I_2, ..., I_n).
是不方便的。列表适用于具有0个或更多元素的(可能是有序的)集合;事实通常用于具有预设列数的表,每行一个事实。这两个表示:
[a, b, c]
(列表)和item(a). item(b). item(c).
(事实表)实际上非常相似。选择一个或另一个是你想要如何使用它的问题,在程序中从一个转换到另一个是非常容易的(并且很常见)。例如,当您定义了(2)时,?- member(X, [a, b, c]).
与?- item(X).
大致相同。 the question you linked的Prolog列表版本将是:
combo(L1, L2, X-Y) :-
member(X, L1),
member(Y, L2).
然后:
?- combo([1,2,3], [4,5], R).
R = 1-4 ;
R = 1-5 ;
R = 2-4 ;
R = 2-5 ;
R = 3-4 ;
R = 3-5.
稍微不那么不便(但仍然没必要)就是写items([a, b, c]).
,所以你有一个参数,一个所有项目的列表。然后,你可以这样做:
?- items(Is),
member(X, Is).
如果你真的有类似items(a, b, c).
,和的东西,你知道你有三个项目,你仍然可以这样做:
?- items(A, B, C),
member(X, [A, B, C]).
如果您在编译时不知道items
的arity,则需要在运行时检查该程序。如果你的程序看起来像你的问题:
items1(1, 2, 3).
items2(4, 5).
然后你可以这样做:
?- current_predicate(items1/N), % figure out the arity of items1
length(Is, N), % make a list of that length
Fact =.. [items1|Is], % create a callable term
Fact, % call the term to instantiate Is
member(X, Is). % enumerate the list
如你所见,非常圆润。
还有一条评论:在Prolog中使用(A,B)
作为“元组”并不常见。对于一对,你通常会写A-B
,如果你不知道你有多少元素,它通常只是一个列表,例如[A,B|Rest]
。有关更多详细信息,请参阅this answer及其下方的评论。