prologprolog-directive-dynamic

Retracting and asserting to another file in Prolog


I'm trying to retract and assert a fact in another file. One (fruit1.pl) contains a couple of facts, and another (fruit.pl) contains a predicate start which designates which fact that another predicate insert_fruit will update:

fruit1.pl

fruit(apple, [[2, yellow], [1, brown]]).
fruit(orange, [[3, orange], [2, orange]]).

fruit.pl

:- dynamic fruit/2.

start :-
    consult('fruit1.pl'),
    File = 'fruit1.pl',
    Name = apple,
    Price = 2,
    Color = red,
    insert_fruit(File, Name, Price, Color). 

insert_fruit(File, Name, Price, Color) :-
   open(File, update, Stream),
   retract(fruit(Name, Information)),
   assert(fruit(Name, [[Price, Color]|Information])),
   close(Stream). 

However insert_fruit is not working as intended, as I believe it needs to include Stream to modify the other file, although I have no idea how (retract(Stream, ...) doesn't work). Is there some I would be able to get the retract and assert predicates to function in the other file?


Solution

  • In SWI-Prolog you can assert/retract facts from a file that is used as a persistent fact store by using library persistency:

    1. You declare fruit/3 as persistent. Optionally: you annotate the arguments with a type for automatic type checking.
    2. You attach a file that will serve as the persistent fact store upon initialization of the fruit module (in this case fruit1.pl).
    3. You add predicates for inserting (i.e., add_fruit/3) and querying (i.e., current_fruit/3) fruity facts. Retraction is handled similarly.
    4. Notice that you can use the fact store in a multi-threaded environment by using with_mutex/2 (especially useful when you start retracting facts as well).

    Code

    :- module(
      fruit,
      [
        add_fruit/3, % +Name:atom, +Price:float, +Color:atom
        current_fruit/3 % ?Name:atom, ?Price:float, ?Color:atom
      ]
    ).
    
    :- use_module(library(persistency)).
    
    :- persistent(fruit(name:atom, price:float, color:atom)).
    
    :- initialization(db_attach('fruit1.pl', [])).
    
    add_fruit(Name, Price, Color):-
      with_mutex(fruit_db, assert_fruit(Name, Price, Color)).
    
    current_fruit(Name, Price, Color):-
      with_mutex(fruit_db, fruit(Name, Price, Color)).
    

    Illustration of use

    Start Prolog, load fruit.pl, execute:

    ?- add_fruit(apple, 1.10, red).
    

    Close Prolog, start Prolog (again), execute:

    ?- current_fruit(X, Y, Z).
    X = apple,
    Y = 1.1,
    Z = red
    

    You are now reading facts from fruit1.pl!

    Illustration of automatic type checking

    As mentioned before, the library also performs type checking for you, e.g.:

    ?- add_fruit(pear, expensive, green).
    ERROR: Type error: `float' expected, found `expensive' (an atom)