Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic rule assertion in SWI-prolog

I am trying to add a rule dynamically to the knowledge base using SWI-prolog where the body of the rule is unknown beforehand.

The desired rule looks something like this:

rule(a) :- fact(1), fact(2).

Normally you would simply state

assert((rule(a):-fact(1),fact(2))).

but the problem is that the facts are decided at runtime (the number of facts is also unknown before the assertion).

That's why I would like to know whether there is a possibility to assert a rule where the body consists of a list of facts such as [fact(1), fact(2)].

like image 508
Tom Avatar asked Oct 31 '10 22:10

Tom


People also ask

What does dynamic mean in Prolog?

dynamic. dynamic. In Prolog, a procedure is either static or dynamic. A static procedure is one whose facts/rules are predefined at the start of execution, and do not change during execution. Normally, the facts/rules will be in a file of Prolog code which will be loaded during the Prolog session.

What are assertions in Prolog?

The prolog assert is a predicate to add a new argument in the application's database using prolog language. It is a meta-predicate to insert facts and clauses in the database as per requirement. It is a function to insert a single clause or rule at the first or last of the database using a programming language.

What is a dynamic predicate?

Predicates that are unknown are implicitly defined as dynamic when they appear first-time in: asserta/1, asserta/2, assertz/1, assertz/2, retract/2, retractall/1. Examples: Use predicate like a dynamic predicate, but the predicate was previously used non-dynamically: NO ?- [user].

How do you assert facts in Prolog?

SWI-Prolog -- assert/1. Assert a clause (fact or rule) into the database. The predicate asserta/1 asserts the clause as first clause of the predicate while assertz/1 assert the clause as last clause. The deprecated assert/1 is equivalent to assertz/1.


2 Answers

We are going to create a rule newrule(X) :- w,x,y,z(X).
The body of a rule is a tuple, a construct in the form (w,x,y...).

For different body lengths, starting with no body:

assert(goal).  
assert(goal:-cond).  
assert(goal:-(cond1,cond2)).

The tuple operator is the comma(`,'), as in ','(a,b) == (a,b).

%%%%
%%%% Name: runtime.pl -- Runtime rule insertion.
%%%%
create_a_rule :- 
    Cond=[w,x,y,z(X)],
    Head=newrule(X),
    list_to_tuple(Cond,Body),
    dynamic(Head),
    assert(Head :- Body),
    listing(Head).

/*
This is a [l,i,s,t], and this is a (t,u,p,l,e).  
Convertng list to tuple:  
[]    -> undefined  
[x]   -> (x) == x  
[x,y] -> (x,y).  
[x,y,z..whatever] = (x,y,z..whatever)  
*/

list_to_tuple([],_) :- 
    ValidDomain='[x|xs]',
    Culprit='[]',
    Formal=domain_error(ValidDomain, Culprit),
    Context=context('list_to_tuple','Cannot create empty tuple!'),
    throw(error(Formal,Context)).

list_to_tuple([X],X).

list_to_tuple([H|T],(H,Rest_Tuple)) :-
    list_to_tuple(T,Rest_Tuple).

:- create_a_rule.
:- listing(newrule).

--

There are two listings. The first listing results from listing() being called in create_a_rule(). The 2nd listing is from the listing() command at the last source line.

?- [runtime].
:- dynamic newrule/1.

newrule(A) :-
    w,
    x,
    y,
    z(A).

:- dynamic newrule/1.

newrule(A) :-
    w,
    x,
    y,
    z(A).

% runtime compiled 0.01 sec, 1,448 bytes
true.
like image 98
frayser Avatar answered Sep 30 '22 15:09

frayser


Suggested alteration to frayser's listing:

list_to_tuple([X],X).

list_to_tuple([A,B],(A,B)).

list_to_tuple([A,B|T],(A,B,Rest_Tuple)) :-
    list_to_tuple(T,Rest_Tuple).

These clauses obviate the need for an exception if the first variable is an empty list: it will simply fail. It also means you'll never hit an assert when backtracking.

However, you might nevertheless WANT the exception clause in place, so you could still put it in to catch cases where an attempted unification with [] was made. (It won't hit it when backtracking, though.)

like image 33
Kaitain Avatar answered Sep 30 '22 17:09

Kaitain