0
votes

I need to get each index of all positive elements in the list and create a new list with all of these indexes

For example,

[-1,2,-5] -> [1]
[1,2,-5] -> [0,1]

I've already had a predicate to get index, but I do not understand how to iterate through each value and return a list at the end. Right now my predicates looks like

indexOf([Element|_], Element, 0) :- !.
indexOf([_|Tail], Element, Index) :-
  indexOf(Tail, Element, Index1),
  !,
  Index is Index1+1.

iterate([],Res) :- Res.
iterate([H|T],Res) :- 
    H>0,
    indexOf([H|T],H,Ind),
    append([],[Ind],Res),
    iterate(T,Res).

iterate([H|T],Res) :- 
    H=<0,
    iterate(T,Res).

But after compilation, I receive this error

**Input** 
iterate([-1,-2,3],X).

**Output**

Sandbox restriction!
Could not derive which predicate may be called from
      call(C)
      iterate([],A)
      iterate([3],A)
      iterate([-2,3],A)
      iterate([-1,-2,3],A)

Pls, tell me, what I'm doing wrong? And why this error appears

2

2 Answers

1
votes

You are using Prolog wrongly:

iterate([],Res) :- Res.

will call the term bound to Res (hopefully the name of a predicate), but not return Res.

SWISH will not let you perform wild calls about which it cannot determine that they are safe, hence the error.

But why such complex code? Do as specified:

% ---
% gimme_positives(List,Positive)
% gimme_positives_2(Idx,List,Positive)
% ---

% We call this

gimme_positives(List,Indexes) :-
   gimme_positives_2(0,List,Indexes).

% This is the "helper" which additionally needs an index

gimme_positives_2(_,[],[]).                  % If List empty, we are done.

gimme_positives_2(Idx,[L|Ls],[Idx|More]) :-  % Case of L positive
   L >= 0,
   IdxPlus is Idx+1,
   gimme_positives_2(IdxPlus,Ls,More).       % recursive call

gimme_positives_2(Idx,[L|Ls],More) :-        % Case of L negative
   L < 0,
   IdxPlus is Idx+1,
   gimme_positives_2(IdxPlus,Ls,More).       % recursive call  

Then:

?- gimme_positives([],X).
X = [] ;
false.

?- gimme_positives([-1,2,-5],X).
X = [1] ;
false.

?- gimme_positives([1,2,-5],X).
X = [0,1] ;
false.

This is actually a case for foldl/4 ... once you feel at home with higher-order predicates and composing lists:

gimme_positives_foldl(List,Indexes) :-
   foldl(
      selector,
      List,               % the list of integers        
      [0,Indexes],        % the initial value: index 0 as first, and the RESULT list as second element 
      [_FinalIndex,[]]).  % the final value: an index we don't care about and the termination of the result list: []

selector(L,[Idx,[Idx|More]],[IdxPlus,More]) :-
   L >= 0,
   IdxPlus is Idx+1.

selector(L,[Idx,More],[IdxPlus,More]) :-
   L < 0,
   IdxPlus is Idx+1.

I can't even fully explain why I write the above like that.

But it works:

?- gimme_positives_foldl([],X).
X = [].

?- gimme_positives_foldl([-1,2,-5],X).
X = [1] ;
false.

?- gimme_positives_foldl([1,2,-5],X).
X = [0,1] ;
false
0
votes

In SWI-Prolog, you can use the predicates nth0/3 and findall/3:

positive_element_indexes(List, Indexes) :-
    findall(Index, 
            (nth0(Index, List, Element), Element > 0),
            Indexes).

Some examples:

?- positive_element_indexes([1,-2,3,-4,5], Indexes).
Indexes = [0, 2, 4].

?- positive_element_indexes([-1,-2,3], Indexes).
Indexes = [2].

?- positive_element_indexes([-1,2,3], Indexes).
Indexes = [1, 2].

?- positive_element_indexes([-1,-2,-3], Indexes).
Indexes = [].