Reputation: 1175
Hello I am new in Prolog and trying to write small program in Prolog in order to learn it....
I have written a program to remove the positional element mean remove(List,2,Ans) will remove all the elements of position 2,4,6,8.... from the list... below is my logic
remove(L,N,Ans):-
length(L,LEN),
T1 is 1 mod N,
add(L,N,[],LEN,T1,Res).
add(L,N,Ans,0,T,Ans).
add([H|T],N,Ans,LEN,0,Res):-
LEN1 is LEN-1,
T1 is 1 mod N,
add(T,N,Ans,LEN1,T1,Res).
add([H|T],N,Ans,LEN,T,Res):-
T =\= 0, LEN =\= 0,
LEN1 is LEN-1,
T1 is T1+1,
T2 is T1 mod N,
append([H],Ans,Result),
add(T,N,Result,LEN1,T2,Res).
but every time I run it is failing when finding add. below is the trace of the program that is have for a particular instance
[trace] ?- remove([1,2,3,4,5,6,7,8],2,X).
Call: (6) remove([1, 2, 3, 4, 5, 6, 7, 8], 2, _G2941) ? creep
Call: (7) length([1, 2, 3, 4, 5, 6, 7, 8], _G3039) ? creep
Exit: (7) length([1, 2, 3, 4, 5, 6, 7, 8], 8) ? creep
Call: (7) _G3041 is 1 mod 2 ? creep
Exit: (7) 1 is 1 mod 2 ? creep
Call: (7) add([1, 2, 3, 4, 5, 6, 7, 8], 2, [], 8, 1, _G3046) ? creep
Fail: (7) add([1, 2, 3, 4, 5, 6, 7, 8], 2, [], 8, 1, _G3046) ? creep
Fail: (6) remove([1, 2, 3, 4, 5, 6, 7, 8], 2, _G2941) ? creep
false.
Does anyone know where the problem is?
Upvotes: 1
Views: 155
Reputation: 60004
Hope you can find your way in your code. I think the better way to learn a language is actually debugging it... lurker' comment already put you on the right track. But I want to show how using builtins can change your perspective (this is of course true for any language, not just Prolog).
remove(L,N,Ans) :- findall(E, (nth1(I,L,E), I mod N =\= 0), Ans).
?- remove([1,2,3,4,5,6,7,8],2,X).
X = [1, 3, 5, 7].
edit when you
Call: (7) add([1, 2, 3, 4, 5, 6, 7, 8], 2, [], 8, 1, _G3046) ? creep
no rule can be matched, specifically T cannot be a list and the number 1
add([H|T],N,Ans,LEN,T,Res):-
that said, I'm not sure how you should correct the code...
Upvotes: 1
Reputation: 74177
A common prolog idiom is the use of a "helper" predicate that actually does the work and carries one or more additional arguments that maintain state. In this case, we need a counter to track our position within the source list.
remove( Xs , N , Ys ) :-
remove( Xs , 1 , N , Ys ). % Note the additional argument (our counter) initialized to 1
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , [X|Ys] ) :- % otherwise,
P mod N =\= 0 , % - if the current position is NOT a multiple of N,
P1 is P+1 , % - we increment the position,
remove(Xs,P1,N,Ys) % - and recurse down, adding the head of the list
. % to the result.
remove( [_|Xs] , P , N , Ys ) :- % otherwise,
P mod N =:= 0 , % - if the current position is a multiple of N,
P1 is P1+1 , % - increment the position,
remove(Xs,P1,N1,Ys) % - and recurse down, discarding the head of the list
. % Easy!
You might note some repetitive code. In the spirit of keeping things DRY, we can refactor it thusly:
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , Ys ) :- % otherwise,
keep_or_discard(X,P,N,Ys,Y1) , % - decided whether to keep or discard the current list head
P1 is P+1 , % - increment the counter
remove( Xs , P1 , N , Y1 ) % - and recurse down.
.
keep_or_discard( _ , P , N , Ys , Ys ) :- % if P is a multiple of N
P mod N =:= 0 , % - discard X,
! . % - and eliminate the choice point.
keep_or_discard( X , _ , _ , Ys , [X|Ys] ) . % otherwise, we keep it.
Some folk dislike the use of the cut to explicitly eliminate choice points, so alternatively, we can do the refactoring via the use of prolog's implication/if-then-else operator:
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , Ys ) :- % otherwise,
( P mod N =:= 0 % - if P is a multiple of N,
-> Y1 = Ys % - then we discard the list head
; [X|Y1] = Ys % - otherwise, we add it to the result list
) , % - and then ...
P1 is P+1 , % - increment the counter
remove( Xs , P1 , N , Y1 ) % - and recurse down.
.
Whether either of these refactorings is clearer, or easier to understand than the original is, of course, a personal choice.
Upvotes: 1