我有接受某些列表的事实。这些列表已排序。
acceptedList([1,2,3]).
acceptedList([4,5,6]).
acceptedList([7,8,9]).
现在,我也想接受接受名单的任何排列。为此,我想对输入列表进行排序并将其与上述事实进行匹配。
我可以使用名称不acceptedList
的谓词来解决这个问题,但我想知道这是否可以以递归方式完成。
这是我的想法:
acceptedList(List) :-
sort(List,SortedList), % Sort the list to match against the facts.
acceptedList(SortedList). % Match against the facts.
我的想法是这个谓词应该接受输入列表,例如 [3,2,1]
.然而,这似乎是一个无限循环,而且由于我乏善可陈的序言知识,我需要一些帮助来理解为什么以及是否可以使用acceptedList
事实和名称相同的谓词来解决这个问题。
Prolog有一个带有谓词permutation/2
的库lists
,可以为给定列表生成所有排列。
所以温可以写:
acceptedList(Lb) :-
acceptedList(La),
permutation(La,Lb).
但是现在我们有一个问题:这个谓词会不断生成列表。由于在它列举了事实之后,它将触发上面定义的谓词,这将再次枚举排列,因此我们将产生排列的排列,排列的排列的排列,等等。这可能不是我们想要的。
对此的解决方案是将事实与谓词分开。因此,我们可以将acceptedList/1
重写为acceptedListFact/1
:
acceptedListFact([1,2,3]).
acceptedListFact([4,5,6]).
acceptedListFact([7,8,9]).
acceptedList(Lb) :-
acceptedListFact(La),
permutation(La,Lb).
因此,我们将La
与一个被陈述为事实的清单统一起来。
现在我们得到以下acceptedList/2
:
?- acceptedList(L).
L = [1, 2, 3] ;
L = [1, 3, 2] ;
L = [2, 1, 3] ;
L = [2, 3, 1] ;
L = [3, 1, 2] ;
L = [3, 2, 1] ;
L = [4, 5, 6] ;
L = [4, 6, 5] ;
L = [5, 4, 6] ;
L = [5, 6, 4] ;
L = [6, 4, 5] ;
L = [6, 5, 4] ;
L = [7, 8, 9] ;
L = [7, 9, 8] ;
L = [8, 7, 9] ;
L = [8, 9, 7] ;
L = [9, 7, 8] ;
L = [9, 8, 7] ;
false.