2010-10-31 12 views
7

Sto provando ad aggiungere una regola dinamicamente alla knowledge base usando SWI-prolog dove il corpo della regola è sconosciuto in precedenza.Asserzione di regole dinamiche in SWI-prolog

La regola desiderata simile a questa:

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

Normalmente si sarebbe semplicemente stato

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

ma il problema è che i fatti sono decisi in fase di esecuzione (il numero di fatti è sconosciuto prima dell'affermazione).

Ecco perché mi piacerebbe sapere se v'è la possibilità di far valere una regola in cui il corpo è costituito da un elenco di fatti, come [Infatti (1), infatti (2)]

risposta

4

Stiamo andando a creare una regola newrule(X) :- w,x,y,z(X).
Il corpo di una regola è una tupla, un costrutto nella forma (w, x, y ...).

Per diverse lunghezze, iniziando con nessun corpo:

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

L'operatore tupla è la virgola (`, '), come 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). 

-

ci sono due elenchi. Il primo elenco risultati da listing() viene chiamato in create_a_rule(). Il secondo elenco è dal comando listing() nell'ultima riga di origine.

?- [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. 
+2

Grazie mille per la soluzione perfetta e molto elaborata! – Tom

+0

@ Tom: se la risposta è "perfetta", perché non lo si accetta? –

+0

Il predicato ['assert'] (http://www.swi-prolog.org/pldoc/man?predicate=assert/1) in questa risposta è deprecato in SWI-Prolog. –

1

consigliata alterazione alla quotazione di Frayser:

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). 

Queste clausole ovviare la necessità di un'eccezione se la prima variabile è una lista vuota: sarà semplicemente fallire. Significa anche che non arriverete mai ad affermare quando tornate indietro.

Tuttavia, si potrebbe tuttavia desiderare la clausola di eccezione sul posto, in modo da poterla comunque inserire per individuare casi in cui è stato effettuato un tentativo di unificazione con []. (Non lo colpirà quando tornerà indietro, però.)

Problemi correlati