Search code examples
prologprolog-directive-dynamic

Prolog - Consult actually cleans current state?


I had the following code for customer creation and listing:

:-dynamic customer/2.

load:-consult('C:\\customers.txt').

save:-tell('C:\\customers.txt'), listing(customer), told.

%New customer
new_customer:-write("Name: "), read(Name), 
customer_code(Code), asserta(customer(Code, Name)), save.

customer_code(Code):- customer(C, _, _, _), Code is C + 1.
customer_code(1).

So far, so good. The problem is, when trying to do more complex search, filtering and reports in general, I had to use retract to clean the current memory state of the customers.

So, before any listing, I tend to consult the file again (calling load):

list_customers:- load, listing(customer).

What goes wrong here is that more times than not, this new load will cause the listing to repeat the last customer added to the database.

Eg:

C:\customers.txt:

:-dynamic customers/2
(2, 'John')
(1, 'Alicia')

listing(customers):

(2, 'John')
(2, 'John')
(1, 'Alicia')

I've been able to avoid this by using retractall before consulting:

load:- reatractall(customer(_,_)), consult('C:\\customers.txt').

Is this a good/bad practice? I don't quite understand what's going on here or why this solves the problem.


Solution

  • The consult predicate, as stated in the documentation in a rather obscure place that references to a deprecated reconsult clause, states that it will reload the clauses that where loaded from the file.

    What does this mean in this case?

    When you first create the entries in the text file, the clauses that where loaded from the file and the clauses that you created are the same.

    The problem arises when you add a new entry. Let's check this with an example to make things clear:

    1) You load the file with consult:

    Now your database and the file will contain the same clauses:

    customers.txt:

    :- dynamic customer/2.
    
    customer(4, 'Juan').
    customer(3, 'Juan').
    customer(2, 'Juan').
    customer(1, 'Juan').
    

    Your Prolog database:

    :- dynamic customer/2.
    
    customer(4, 'Juan').
    customer(3, 'Juan').
    customer(2, 'Juan').
    customer(1, 'Juan').
    

    So far, so good.

    2) You add a new customer and save it to the file using tell / told:

    customers.txt:

    :- dynamic customer/2.
    
    customer(5, 'Juan').
    customer(4, 'Juan').
    customer(3, 'Juan').
    customer(2, 'Juan').
    customer(1, 'Juan').
    

    Your Prolog database:

    :- dynamic customer/2.
    
    customer(5, 'Juan').
    customer(4, 'Juan').
    customer(3, 'Juan').
    customer(2, 'Juan').
    customer(1, 'Juan').
    

    Still, no issues. Here comes the real problem:

    3) You reload the file:

    customers.txt:

    :- dynamic customer/2.
    
    customer(5, 'Juan').
    customer(4, 'Juan').
    customer(3, 'Juan').
    customer(2, 'Juan').
    customer(1, 'Juan').
    

    Your Prolog database:

    :- dynamic customer/2.
    
    customer(5, 'Juan').
    customer(5, 'Juan').
    customer(4, 'Juan').
    customer(3, 'Juan').
    customer(2, 'Juan').
    customer(1, 'Juan').
    

    Okay, what happened here? If you remember, we previously saw that consult reload clauses that where loaded from the file.

    So, the clauses we reloaded are:

    customer(4, 'Juan').
    customer(3, 'Juan').
    customer(2, 'Juan').
    customer(1, 'Juan').
    

    This leaves us with a clause, customer(5, 'Juan'), that wasn't loaded from the file the first time. So now we have to add it to our database, thus resulting in:

    customer(5, 'Juan').
    customer(5, 'Juan').
    customer(4, 'Juan').
    customer(3, 'Juan').
    customer(2, 'Juan').
    customer(1, 'Juan').