How to write predicate convert/2 in prolog?

后端 未结 2 890
离开以前
离开以前 2021-01-22 19:11

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

? - conv         


        
2条回答
  •  囚心锁ツ
    2021-01-22 19:57

    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]).
    

提交回复
热议问题