retract_exactly/1

Help requests on developing Logtalk applications

Moderator: Paulo Moura

Post Reply
Parker
Posts: 33
Joined: Wed Feb 27, 2008 2:51 pm

retract_exactly/1

Post by Parker » Thu Mar 05, 2009 11:42 am

Hi Paulo,

Could you advise me on how to implement Richard O'Keefe's retract_exactly/1? My understanding is that it is still not possible in Logtalk without reaching through to the backend Prolog.

Code: Select all

retract_exactly(Clause) :-
    ( nonvar(Clause) -> Clause = :-(Head,Body)
    ; Head = Clause, Body = true
    ),
    must_be_callable(Head),
    functor(Head, F, N),
    functor(Skel, F, N),
    clause(Skel, Rest, DbRef),
    :-(Skel,Rest) =@= :-(Head,Body),
    erase(DbRef).
Here is the rationale for the retract_exactly/1:
Consider these two cases:
Case 1. clause db contains:
p(a)
p(X)

Now, retract(p(Z)) will remove p(a).

Case 2. clause db contains the same clauses but in reverse order:
p(X)
p(a)

Again, retract(p(Z)) and this time p(X) is removed.

What if a predicate is required that retracts only structurally-equivalent clauses - ie retract_exactly(p(Z)) in both cases above removes p(X) and leaves p(a).
I first raised this on the SWI-prolog mailing list back in 2007 and I still have the issue.
http://osdir.com/ml/lang.swi-prolog.gen ... 00008.html

Just wondering if this can be done in Logtalk yet.

Cheers,
Parker

Paulo Moura
Logtalk developer
Posts: 475
Joined: Sat May 05, 2007 8:35 am
Location: Portugal
Contact:

Re: retract_exactly/1

Post by Paulo Moura » Thu Mar 05, 2009 2:57 pm

Parker wrote: Could you advise me on how to implement Richard O'Keefe's retract_exactly/1? My understanding is that it is still not possible in Logtalk without reaching through to the backend Prolog.
Correct. Database predicates such as clause/3 must be handled by the Logtalk compiler in order to translate their arguments (to take into account the way Logtalk compiles object and category predicates) before calling the corresponding Prolog built-in predicates. Predicates such as clause/3 or erase/1 or not standard and are only available in some Prolog compilers. Adding them as Logtalk built-in database methods would require emulating them for Prolog compilers laking the corresponding built-in predicates.

A possible solution would be to use an extra goal in the clause body whose argument would be a unique reference (generated e.g. using the "gensym" library). This goal would be defined by a single clause that would always succeed. Something like this (not tested):

Code: Select all

db_ref(_).

my_assertz((Head :- Body), Ref) :-
	!,
	gensym::gensym('db_ref', Ref),
	assertz((Head :- (db_ref(Ref), Body))).

my_assertz(Fact, Ref) :-
	!,
	gensym::gensym('db_ref', Ref),
	assertz((Fact :- db_ref(Ref))).

my_clause(Head, Body, Ref) :-
	clause(Head, (db_ref(Ref), Body)).

my_retract((Head :- Body), Ref) :-
	!,
	retract((Head :- (db_ref(Ref), Body))).

my_retract(Fact, Ref) :-
	retract((Head :- db_ref(Ref))).

my_retract_exactly(Clause) :-
	(	nonvar(Clause) ->
		Clause = (Head :- Body)
	;	Head = Clause,
		Body = true
	),
	(	callable(Head) ->
		true
	;	this(This),
		sender(Sender),
		throw(error(type_error(callable, Head), This::retract_exactly(Clause), Sender))
	),
	functor(Head, Functor, Arity),
	functor(HeadTemplate, Functor, Arity),
	my_clause(HeadTemplate, BodyTemplate, Ref),
	(HeadTemplate :- BodyTemplate) =@= (Head :- Body),
	my_retract((HeadTemplate :- BodyTemplate), Ref).
Would this solution work in your case?
Paulo Moura
Logtalk developer

Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests