使用 repeat 对序言中的事实集合进行排序

Using repeat to sort a collection of facts in prolog

我有一组事实 set/2,其中第一个变量是集合的标识符,第二个是与标识符关联的值。
例如:

set(a,2).
set(a,c).
set(a,1).
set(a,a).
set(a,3).
set(a,b).

我需要构造一个谓词 ordering/2(使用重复运算符),它将按字典顺序输出特定集合的值。 例如

?- ordering(a,Output).

会导致

[1,2,3,a,b,c].

到目前为止我所做的是这段代码:

ordering(Input,Output):-    
    findall(X,set(Input,X),List),
    repeat,
    doSort(List)
    sort(List, OrderedList),
    Output = OrderedList. 

这里的想法是谓词将找到与特定输入关联的集合的所有值,并将列表变量与它们统一起来。现在我们有了未排序的列表。这是我不完全确定的部分。谓词应该继续在列表上使用某种特定的 doSort,然后使用 sort/2 检查列表,如果它是按字典顺序排列的,则将其与输出统一。

任何人都可以澄清我是否走在正确的道路上,如果是,那么应该如何实施 doSort?

好吧,我在@Daniel lyon 的帮助下尝试了一种答案:

ordering(Input,Output):-    
   findall(X,set(Input,X),List),
    repeat,
    permutation(List,PermutationList),
    sort(PermutationList, SortedList),
    Output= SortedList , !. 

大体思路是一样的,对于repeat循环,predicate会统一List和PermutationList,尝试它的所有变体并用sort/2检查它们的正确性,直到达到正确的排列,统一它与SortedList,之后它将Output与SortedList统一。剪切就在那里,所以我只会得到一次输出。

?- % init test DB
|    maplist([X]>>assert(set(a,X)), [c,b,a,1,2,3]).
true.

?- % find first
|    set(a,X), \+ (set(a,Y), Y @< X).
X = 1 ;
false.

?- % find next, given - hardcoded here as 1 - previous
|    set(a,X), X @> 1, \+ (set(a,Y), Y @> 1, Y @< X).
X = 2 ;
false.

现在我们可以尝试使这些查询可重用:

ordering(S,[H|T]) :- first(S,H), ordering(S,H,T).

first(S,X) :- set(S,X), \+ (set(S,Y), Y @< X).
next(S,P,X) :- set(S,X), X @> P, \+ (set(S,Y), Y @> P, Y @< X).

ordering(S,P,[X|T]) :- next(S,P,X), ordering(S,X,T).
ordering(_,_,[]).

正确地说,我们需要在某处进行切割。你能认出那个地方吗?