我有接受某些名单的事实。这些列表已经过排序。
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]
。
然而,这似乎进入了一个无限循环,并且由于我乏味的prolog知识,我需要一些帮助来理解为什么以及是否可以使用acceptedList
事实和名称相同的谓词来解决这个问题。
答案 0 :(得分:3)
Prolog有一个库lists
,其谓词permutation/2
可以生成给定列表的所有排列。
所以你可以写:
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
s:
?- 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.