2010-10-31 13 views
7

Estoy intentando agregar una regla dinámicamente a la base de conocimiento utilizando SWI-prolog donde el cuerpo de la regla se desconoce de antemano.Aserción de regla dinámica en SWI-prolog

La regla deseada ve algo como esto:

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

Normalmente se limitan a afirmar

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

pero el problema es que los hechos se deciden en tiempo de ejecución (el número de hechos también se desconoce antes de la afirmación).

Por eso me gustaría saber si existe la posibilidad de hacer valer una en la que el cuerpo se compone de una lista de hechos tales como [hecho (1), hecho (2)]

Respuesta

4

Vamos a crea una regla newrule(X) :- w,x,y,z(X).
El cuerpo de una regla es una tupla, una construcción con el formato (w, x, y ...).

para diferentes longitudes de cuerpo, empezando con ningún cuerpo:

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

El operador tupla es la coma (`, '), como en ', '(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). 

-

Hay dos listados. Los primeros resultados de listado de listing() se llaman en create_a_rule(). La segunda lista es del comando listing() en la última línea fuente.

?- [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

¡Muchas gracias por la solución perfecta y muy elaborada! – Tom

+0

@Tom: si la respuesta es "perfecta", ¿por qué no * la acepta? –

+0

El predicado ['assert'] (http://www.swi-prolog.org/pldoc/man?predicate=assert/1) en esta respuesta está en desuso en SWI-Prolog. –

1

alteración que se sugiera a la lista de 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). 

Estas cláusulas elimina la necesidad de una excepción si la primera variable es una lista vacía, sino que sólo se producirá un error. También significa que nunca golpearás una afirmación al retroceder.

Sin embargo, es posible que desee la cláusula de excepción en su lugar, por lo que aún podría ponerla en los casos donde se intentó unificar con []. (Sin embargo, no funcionará cuando se retroceda).