Prolog search for possible combination for subtracting 2 elements from a list

前端 未结 2 807
情深已故
情深已故 2021-01-23 12:34

This is an extended problem from this page. Prolog possible removal of elements in a list

For example, for a list X = [1,2,3], I can subtract like following:

sub

2条回答
  •  醉话见心
    2021-01-23 12:48

    Here's an alternative solution which uses more fundamental operations. Like @gusbro's solution, it breaks the problem down into (1) examining each element in the list as a range value for reduction, and (2) reducing one more element in the rest of the list based upon the current value in the range defined in (1).

    reduce([H|T], R) :-
        reduce_by([H|T], H, R).   % Reduce the list [H|T] by H yielding R
    reduce([H|T], [H|R]) :-
        reduce(T, R).             % Do the same for the rest of the list
    
    % reduce_by(L, X, R) reduces two elements in L by each value in the range 1 to X
    reduce_by([X|T], X, R) :-
        reduce_once(T, X, R).     % Drop the element if diff is 0, reduce one more from rest
    reduce_by([H|T], X, [Y|R]) :-
        H > X,
        Y is H - X,               % reduce current element by X, reduce one more from rest
        reduce_once(T, X, R).
    reduce_by(L, X, R) :-
        X1 is X - 1,              % decrement reduction amount and reduce by that amount
        X1 > 0,
        reduce_by(L, X1, R).
    
    % reduce_once(L, X, R) finds one element in L which is >= X and reduces it, else fails
    reduce_once([X|T], X, T).     % same value, it's just removed (difference is 0)
    reduce_once([H|T], X, [Y|T]) :-
        H > X,                    % reduce the value by X if we can
        Y is H - X.
    reduce_once([H|T], X, [H|R]) :-
        reduce_once(T, X, R).     % skip this value and reduce a different value
    

    Results:

    | ?- reduce([1,2,3], L).
    
    L = [1,3] ? a
    
    L = [2,2]
    
    L = [1,1]
    
    L = [1,1,2]
    
    no
    | ?-
    

    There's a key difference in Prolog versus when programming in Java or C# or other procedural languages. Prolog, through backtracking, will attempt to find all instantiations of the arguments that will make a predicate succeed. See this answer for further details. When writing Prolog predicates (or rules), you need to think about how to state the rules such that they succeed for cases that you want them to. Prolog will do all the work through backtracking to iterate through the all of the possible solutions to success.

    For example, in the case of reduce_once, we have one clause that reads:

    reduce_once([X|T], X, T).
    

    So this will succeed as long as the arguments can be unified with the inputs. Specifically, a query such as reduce_once([1,2,3], 1, T). will succeed with T = [2,3]. But then once it succeeds, Prolog sees there are other rules for the same predicate, and will attempt those as well. Thus, reduce_once([1,2,3], 1, [1|R]) :- reduce_once([2,3], 1, R). will be executed, etc.

提交回复
热议问题