问题
I have a set of facts set/2 where the first variable is the identifier for the set and the second is the value associated with the identifier.
For example:
set(a,2).
set(a,c).
set(a,1).
set(a,a).
set(a,3).
set(a,b).
I need to construct a predicate ordering/2 (using the repeat operator) which will output the values of a specific set in their lexicographic order. For example
?- ordering(a,Output).
Would result in
[1,2,3,a,b,c].
What I have made thus far is this code:
ordering(Input,Output):-
findall(X,set(Input,X),List),
repeat,
doSort(List)
sort(List, OrderedList),
Output = OrderedList.
The idea here is that the predicate will find all values of the set associated with the specific Input and unify the List variable with them. Now we have the unsorted List. Here comes the part I'm not completely sure on. The predicate is supposed to keep using some sort of specific doSort on the List, then check the List with sort/2 and if it's lexicographically ordered, unify it with the Output.
Can anyone clarify if I'm on the correct path and if yes then how should the doSort be implemented?
回答1:
Alright, I tried a sort of answer for this using @Daniel lyon's help:
ordering(Input,Output):-
findall(X,set(Input,X),List),
repeat,
permutation(List,PermutationList),
sort(PermutationList, SortedList),
Output= SortedList , !.
The general idea is the same, for the repeat cycle, the predicate will unify the List with PermutationList, try all variants of it and check for their correctness with sort/2 until it achieves the correct permutation, unifying it with SortedList, after that it will unify the Output with SortedList. The cut is there so I will only get the Output once.
回答2:
?- % 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.
now we can try to make these queries reusable:
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(_,_,[]).
To be correct, we need a cut somewhere. Can you spot the place ?
来源:https://stackoverflow.com/questions/47144989/using-repeat-to-sort-a-collection-of-facts-in-prolog