简体   繁体   中英

How to write predicate convert/2 in prolog?

I want to write a predicate convert/2. It should work like this

? - convert([a,[a,a],[a,b],[b,a],[[a,b]],[d],c],X).
X = [a,c,[a],[d],[a,b],[[a,b]]]
yes

? - convert([[a,[a,b]],[a,[c,b]],[[a,b],a]], X).
X = [[a,[a,b]],[a,[b,c]]]
yes

? - convert([[a,b],[a,[a]],[a,b,c]],X).
X = [[a,b],[a,[a]],[a,b,c]]
yes

I know ,that i have to find length of list first. Then i have to sort it and finally i have to merge duplicating elements.

So, without knowing exactly what your sorting algorithm is, I have created a somewhat generic example to demonstrate the concept:

convert(X, X) :- \+is_list(X).
convert([],[]).
convert([InHead|InTail], OutList) :-
    convert(InHead, OutHead),
    convert(InTail, OutTail),
    append([OutHead], OutTail, UnsortedList),
    sort(UnsortedList, DeduplicatedList),
    custom_sort(DeduplicatedList, OutList).

custom_sort(List,Sorted) :-
    permutation(List,Sorted),
    is_sorted(Sorted).

is_sorted([]).
is_sorted([_]).
is_sorted([X,Y|T]) :- 
    % perform any number of tests on X and Y here
    % default is:
    X @=< Y,
    is_sorted([Y|T]).

This recursively converts each list in the list, then uses the built-in sort to remove duplicates, then applies a custom sort (built on naive sort).

I initially thought that I had cracked your sorting algorithm (sort by depth of the list (where an atom has depth 0), then by length of the list (where an atom has length 0), then by elements of the list) and came up with the following:

list_length(X, 0) :- 
    \+is_list(X).
list_length(X, Y) :- 
    is_list(X), length(X, Y).

list_depth(X, 0) :- \+is_list(X).
list_depth([], 0).
list_depth([Head|Tail], Y) :-
    list_depth(Head, YH),
    list_depth(Tail, YTP),
    YT is YTP - 1,
    Y is max(YH, YT) + 1.

is_sorted([X,Y|T]) :- 
    list_length(X, XL), 
    list_length(Y, YL),
    list_depth(X, XD),
    list_depth(Y, YD),
    ( XD < YD ; 
      ( XD = YD,
        ( XL < YL ; 
          ( XL = YL, 
            X @=< Y) 
        )
      )
    ),
    is_sorted([Y|T]).

... but this fails for your third example, where [a,[a]],[a,b,c] has depth 2 followed by depth 1, so I present the code above for your enjoyment more than anything else.

Edit: The comment from Boris was enough for me to realise that sorting by flattened length then depth works for all of your examples, which looks like this:

list_length(X, 0) :- 
    \+is_list(X).
list_length(X, Y) :- 
    is_list(X), 
    flatten(X, Z), 
    length(Z, Y).

list_depth(X, 0) :- \+is_list(X).
list_depth([], 0).
list_depth([Head|Tail], Y) :-
    list_depth(Head, YH),
    list_depth(Tail, YTP),
    YT is YTP - 1,
    Y is max(YH, YT) + 1.

is_sorted([X,Y|T]) :- 
    list_length(X, XL), 
    list_length(Y, YL),
    list_depth(X, XD),
    list_depth(Y, YD),
    ( XL < YL ; 
      ( XL = YL,
        ( XD < YD ; 
          ( XD = YD, 
            X @=< Y) 
        )
      )
    ),
    is_sorted([Y|T]).

Ok, but can you replace built-in function 'sort' by some other? this is most important here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM