SWI Prolog list subtract gives error: Out of local stack

Viewed 59

I'm running some Prolog rule which uses the subtract function and in the stack trace, I found the source of error to be this:

lists:subtract([b, d | _], [b, d] , [r]) ? creep
ERROR: Out of local stack

The original call was:

member(b, X), member(d, X), subtract(X, [b, d], [r]).

and the expected output is [b, d, r].

I'm new to Prolog and unable to understand the source of error and how to fix it. Please help.

2 Answers

unable to understand the source of error and how to fix it.

Just take your query and look at the first two goals alone:

?- member(b, X), member(d, X).
   X = [b,d|_A]
;  X = [b,_A,d|_B]
;  X = [b,_A,_B,d|_C]
;  X = [b,_A,_B,_C,d|_D]
;  X = [b,_A,_B,_C,_D,d|_E]
;  ... .

Just these two goals produce already infinitely many answers. So no matter what follows, your query will never terminate. By chance, you may happen to get a solution, but more often than not you will end in some loop.

So first of all you need to fix this somehow.

Then consider the meaning of subtract/3 in SWI:

?- subtract([b,d,r], [b,d], [r]).
true.

?- subtract([b,d,X], [b,d], [r]).
false. % ?? why not X = r?

From this alone you can see that subtract/3 is not a relation. So you cannot use it as a relation like, say, append/3.

To fix this and keep as close to your original query, use library(reif) and library(lambda):

?- S1=[b,d,X], S2 = [b,d], tpartition(S2+\E^memberd_t(E,S2),S1,_,[r]).
   S1 = [b,d,r], X = r, S2 = [b,d].

From SWI Prolog manual :

The library(lists) contains a number of old predicates for manipulating sets represented as unordered lists, notably intersection/3, union/3, subset/2 and subtract/3. These predicates all use memberchk/2 to find equivalent elements. As a result these are not logical while unification can easily lead to dubious results.

You are having this problem because subtract isn't pure and needs it's first two Arguments to be instantiated hence the + sign in it's documentation .

subtract(+Set, +Delete, -Result)

you can instead use union/3

union(+Set1, +Set2, -Set3)

you can know more about other mode indicators in here.

Related