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)]
.
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.
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.
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].
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.
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.
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With