Search code examples
prolog

Simple recursive prolog program to add elements


I am trying to calculate the sum of values given. My attempt:

element(0, 988).
element(1, 5434).
element(2, 5433).
element(3, 4543).
element(4, 827).

addElements(5, 0).

addElements(INDEX, SUM):-     %sums from given index to the end of array
    element(INDEX, VALUE),
    addElements(INDEX+1, SUM-VALUE).

My query:

addElements(0,X).

This is not working. Is it a syntactic error?


Solution

  • To evaluate arithmetic expressions in Prolog, you need to use the ISO built-in predicate is/2:

    ?- Index = 1, NewIndex is Index + 1.
    Index = 1,
    NewIndex = 2.
    
    ?- Accumulator = 10, NewAccumulator is Accumulator + 5.
    Accumulator = 10,
    NewAccumulator = 15.
    

    Thus, assuming the indices are consecutive integers, a possible solution is:

    add_elements(Index, Sum) :-
        add_elements_loop(Index, 0, Sum).
    
    add_elements_loop(Index, Accumulator, Sum) :-
        not(element(Index, _)),              % index out of range!
        Sum = Accumulator.
    
    add_elements_loop(Index, Accumulator, Sum) :-
        element(Index, Value),
        NewIndex is Index + 1,
        NewAccumulator is Accumulator + Value,
        add_elements_loop(NewIndex, NewAccumulator, Sum).
    
    element(0, 70).
    element(1, 30).
    element(2, 10).
    element(3, 20).
    element(4, 80).
    

    Examples:

    ?- add_elements(0, S).
    S = 210 ;
    false.
    
    ?- add_elements(3, S).
    S = 100 ;
    false.
    

    An improved version of this code, which avoids the redundant call of the predicate element/2 and eliminates the spurious choice point, is as follows:

    add_elements(Index, Sum) :-
        add_elements_loop(Index, 0, Sum).
    
    add_elements_loop(Index, Accumulator, Sum) :-
        (   element(Index, Value)                             % if
        ->  NewIndex is Index + 1,                            % then 
            NewAccumulator is Accumulator + Value,
            add_elements_loop(NewIndex, NewAccumulator, Sum)
        ;   Sum = Accumulator ).                              % else
    
    ?- add_elements(0, S).
    S = 210.
    
    ?- add_elements(3, S).
    S = 100.