Re: Gprolog member/2 error ?!
Nicolas Pelletier <[email protected]>
| Newsgroups | gmane.comp.gnu.prolog.general |
|---|---|
| Message-ID | <[email protected]> |
Hello, On Mon, Aug 23, 2010 at 01:32, Pedro Fialho <[email protected]> wrote: > Hi all, > > I found a strange error on my gprolog coding, namely on the source: > > pred1([R-C-P|Ls], [R-C-P|Ls1]):- > memberchk(rel(_,X,Y), C), > memberchk(rel(_,Y,_), C), > nth(1,P,Z), > ... [snip!] > Also tried with member/2 but the List is always changed on exit of the > secound call to member/2. Notice the rel(de,_198617,_198661) predicate > is changed to rel(de,_198617,_198617) although member/2 is not stated > as a destructive process. memberchk/2 and member/2 are not destructive, but they will still try to unify their first argument with an element of the list. This unification will result in variables being shared, which is what you are seeing here. The following, simpler, example also shows unification happening: bash-4.1$ gprolog GNU Prolog 1.3.0 By Daniel Diaz Copyright (C) 1999-2007 Daniel Diaz | ?- [user]. compiling user for byte code... p(X, Y, L) :- memberchk(rel(_,X,Y), L), memberchk(rel(_,Y,_), L). user compiled, 4 lines read - 648 bytes written, 26169 ms yes | ?- trace, p(X, Y, [rel(A, B, C)]). The debugger will first creep -- showing everything (trace) 1 1 Call: p(_16,_17,[rel(_18,_19,_20)]) ? 2 2 Call: memberchk(rel(_93,_16,_17),[rel(_18,_19,_20)]) ? 2 2 Exit: memberchk(rel(_18,_16,_17),[rel(_18,_16,_17)]) ? 3 2 Call: memberchk(rel(_122,_17,_124),[rel(_18,_16,_17)]) ? 3 2 Exit: memberchk(rel(_18,_16,_16),[rel(_18,_16,_16)]) ? 1 1 Exit: p(_16,_16,[rel(_18,_16,_16)]) ? C = B X = B Y = B yes {trace} | ?- To prevent unification from happening in the second memberchk/2, you need to undo the substitution performed during unification with a double negation: | ?- [user]. compiling user for byte code... p(X, Y, L) :- memberchk(rel(_,X,Y), L), \+ \+ memberchk(rel(_,Y,_), L). user compiled, 4 lines read - 742 bytes written, 28446 ms yes | ?- trace, p(X, Y, [rel(A, B, C)]). The debugger will first creep -- showing everything (trace) 1 1 Call: p(_16,_17,[rel(_18,_19,_20)]) ? 2 2 Call: memberchk(rel(_93,_16,_17),[rel(_18,_19,_20)]) ? 2 2 Exit: memberchk(rel(_18,_16,_17),[rel(_18,_16,_17)]) ? 3 2 Call: \+ \+memberchk(rel(_122,_17,_124),[rel(_18,_16,_17)]) ? 4 3 Call: \+memberchk(rel(_122,_17,_124),[rel(_18,_16,_17)]) ? 5 4 Call: memberchk(rel(_122,_17,_124),[rel(_18,_16,_17)]) ? 5 4 Exit: memberchk(rel(_18,_16,_16),[rel(_18,_16,_16)]) ? 4 3 Fail: \+memberchk(rel(_122,_17,_124),[rel(_18,_16,_17)]) ? 3 2 Exit: \+ \+memberchk(rel(_122,_17,_124),[rel(_18,_16,_17)]) ? 1 1 Exit: p(_16,_17,[rel(_18,_16,_17)]) ? X = B Y = C yes Note this is an intrinsic property of the unification algorithm, and as such, present in all Prologs. In other words, you will have to take into account which variables you wish to unify, and when, if going this route. If not, you might want to investigate using dynamic predicates to store partially instantiated data you want to keep (e.g. assert and retract). Hope this helps, -- Nicolas