Search code examples
prologfact

Prolog: retract fact by it's name


I want to retract fact, but I have not direct access to the name of fact. To get anything from this fact I'd use following code:

facts.pl file:

:- dynamic fact/2.

fact(a, b).
fact(b, e). 
fact(a, c). 
fact(e, d). 
fact(c, d). 
fact(d, f). 
fact(d, g).

solution.pl file:

someProcedure(StructureName) :-
    call(StructureName, a, X).

Now how could I retract that dynamic fact from memory in solution.pl?

I've tried something like:

deleteProcedure(StructName, A, B) :-
    retract(call(StructName, A, B)).

But I get error:

ERROR: retract/1: No permission to modify static procedure `call/3'
ERROR: Defined at /usr/lib/swi-prolog/boot/init.pl:217

Solution

  • You can use the univ predicate (=../2) to build the term to retract.

    retract_fact(Name, A, B) :-
      Fact =.. [Name,A,B],
      retract(Fact).
    

    Note this solution accepts only atoms as the Name, so it is tailored to your example:

    ?- retract_fact(fact,a,b).
    true.
    

    and will not work if you pass a compound term, e.g.:

    :- dynamic fact/3.
    fact(a, b, c).
    
    ?- retract_fact(fact(a),b,c).
    ERROR: Type error: `atom' expected, found `fact(a)' (a compound)
    

    Here is a revised solution accepting compound terms:

    retract_fact(Term, A, B) :-
      Term =.. L,
      append(L, [A,B], L1),
      Fact =.. L1,
      retract(Fact).
    

    Sample run:

    ?- retract_fact(fact(a),b,c).
    true.
    
    ?- retract_fact(fact,b,e).
    true.