Possible database update problem

I’m on the latest daily build for windows (version 10.1.18-3-gf379af528). I noticed that some times the database state is not correctly updated after I make a change to my code and call make/0.

For example, I remove a couple of clauses from my program after which the program should fail, then I call make/0 and when I call my program at the top level it succeeds.

So I start a fresh session without making any changes to my code and the same query succeeds. The difference between the two sessions is that one was updated with make/0 and the other by re-consulting the source file in a fresh session.

More confusingly, when I list my program with listing/0 in the session where my program succeeds, I see the removed clauses are not there. And yet my program behaves as if they are (and I can see that when I trace it).

This doesn’t seem to happen all the time, but I’ll try to make a simple example as much as I can.

Btw, I’m working with some DCGs so the problem may be with the DCG interpreter. Or not.

OK, this is not a simple example but I’m not sure how to make this simpler.

This is the output of two sessions, the first one where my query succeeds when it should fail and the second when it fails correctly. I also list the contents of the database which are the same in both sessions (and this is why I suspect a bug in SWI rather than a bug in my code).

First session, succeeds when it should fail:

119 ?- _I = 9, ground_csg(abc,[a,b,c],['S'],_I,Ps).
Ps = [a, a, a, b, b, b, c, c, c] .

120 ?- listing(abc).
grammars:abc(['S'|Ss], [a, 'S', 'B', 'C'|A], B) :-
    abc(Ss, A, B).
grammars:abc(['S'|Ss], [a, 'B', 'C'|A], B) :-
    abc(Ss, A, B).
grammars:abc(['C', 'B'|Ss], ['B', 'C'|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([a, 'B'|Ss], [a, b|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([b, 'B'|Ss], [b, b|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([b, 'C'|Ss], [b, c|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([c, 'C'|Ss], [c, c|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc(['B'|Ss], ['B'|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc(['C'|Ss], ['C'|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([b|Ss], [b|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([c|Ss], [c|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([], A, B) :-
    A=B.

true.

Second session, fails when it should fail:

101 ?- _I = 9, ground_csg(abc,[a,b,c],['S'],_I,Ps).
false.

102 ?- listing(abc).
grammars:abc(['S'|Ss], [a, 'S', 'B', 'C'|A], B) :-
    abc(Ss, A, B).
grammars:abc(['S'|Ss], [a, 'B', 'C'|A], B) :-
    abc(Ss, A, B).
grammars:abc(['C', 'B'|Ss], ['B', 'C'|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([a, 'B'|Ss], [a, b|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([b, 'B'|Ss], [b, b|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([b, 'C'|Ss], [b, c|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([c, 'C'|Ss], [c, c|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc(['B'|Ss], ['B'|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc(['C'|Ss], ['C'|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([b|Ss], [b|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([c|Ss], [c|A], B) :-
    !,
    C=A,
    abc(Ss, C, B).
grammars:abc([], A, B) :-
    A=B.

true.

Note that the listing is the same in both sessions. Unless I’m missing something (possible) the behaviour should be the same in both sessions, if both sessions are working off the same database.

This is the code. First my DCG, with the rule for ‘a’ commented-out so that it should fail:

abc(['S'|Ss]) --> [a,'S','B','C'], abc(Ss).
abc(['S'|Ss]) --> [a,'B','C'], abc(Ss).
abc(['C','B'|Ss]) --> ['B','C'], !, abc(Ss).
abc([a,'B'|Ss]) --> [a,b], !, abc(Ss).
abc([b,'B'|Ss]) --> [b,b], !, abc(Ss).
abc([b,'C'|Ss]) --> [b,c], !, abc(Ss).
abc([c,'C'|Ss]) --> [c,c], !, abc(Ss).

abc(['B'|Ss]) --> ['B'], !, abc(Ss).
abc(['C'|Ss]) --> ['C'], !, abc(Ss).
%abc([a|Ss]) --> [a], !, abc(Ss).
abc([b|Ss]) --> [b], !, abc(Ss).
abc([c|Ss]) --> [c], !, abc(Ss).
abc([]) --> [].

And here’s the meta-interpreter in case it’s needed to test this:

%!      ground_csg(+Symbol,+Terminals,+Input,+Length,?String)
%!      is nondet.
%
%       Meta-interpreter for Context Sensitive Grammars in DCG notation.
%       
ground_csg(S,Ts,Is,K,Os):-
        N = K
        ,parse(S,Is,Ss)
        ,ground_csg_(S,Ts,Ss,N,Os).

%!      ground_csg_(+Symbol,+Terminals,+Input,+K,-Output) is nondet.
%
%       Business end of ground_csg/5.
%
ground_csg_(_S,Ts,Is,N,Is):-
        length(Is,M)
        ,M =:= N
        ,terminal_string(Ts,Is)
        ,!.
ground_csg_(S,Ts,Is,N,Os):-
        length(Is,M)
        ,M =< N
        ,\+ terminal_string(Ts,Is)
        ,parse(S,Is,Ss)
        ,ground_csg_(S,Ts,Ss,N,Os).


%!      parse(+Symbol,+Inputs,-Parse) is nondet.
%
%       Thin wrapper around phrase/3 to setup a parse.
%
parse_(S,Is,Ss):-
        S_ =.. [S,Ss]
        ,phrase(S_,Is).
parse(S,Is,Ss):-
        S_ =.. [S,Is]
        ,phrase(S_,Ss).


%!      terminal_string(+Terminals,+String) is det.
%
%       True if String is made up of only Terminals.
%
terminal_string(Ts,Ss):-
        maplist(sort,[Ts,Ss],[Ts_s,Ss_s])
        ,ord_subset(Ss_s,Ts_s).

Simple enough for Claude to track down. Fixed. It is indeed (only) related to reloading static code that could find stale clauses through the old index.

Wonerful! I’ll get the next daily build then. Thank you @Jan and Claude.