Gorgias port

Discussion on porting Prolog applications to Logtalk

Moderator: Paulo Moura

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

Re: Gorgias port

Post by Paulo Moura » Tue Apr 08, 2008 11:51 am

Victor NOEL wrote:I understand more now, so I applied your advices and wrote a little example like that :

Code: Select all

:- category(ctg, implements(monitoring)).

	:- public(test1/3).

	test1(X, Y, Z) :-
		test(X, Y, Z).

	test(X, Y, Z) :-
		a(1, X), a(2, Y), a(3, Z).

	after(_, test(X, Y, Z), _) :-
		writeq(X), write(' '), writeq(Y), write(' '), writeq(Z), nl.

	a(1, a).
	a(2, b).
	a(3, c).

:- end_category.


:- object(obj,
	implements(monitoring),
	imports(ctg)).

	:- threaded.
	
	after(Object, Message, Sender) :-
	   ::after(Object, Message, Sender).

:- end_object.
The above event handlers will not work as you can only monitor messages sent using the ::/2 control construct; the predicate test/3 is called directly and is thus invisible as far as events are concerned. In this case, you will need to drop the predicate test1/3 and make test/3 public.
Victor NOEL wrote:And if I activate the event handler, I get a out of local stack error :

Code: Select all

?- obj::test1(X, Y, Z).
X = a,
Y = b,
Z = c.

?- define_events(after, _, _, _, obj).
true.

?- obj::test1(X, Y, Z).
ERROR: Out of local stack
I guess there is something wrong in what I wrote :) Maybe the after event (in obj) is called every time the after event (in ctg) is called ?
I would be worried if you did not get the error above as I made a typo in my previous message! Sorry about that (I've already edited the post and corrected the typo). You get an "out of stack" error because you're using the "message to self" control construct ::/1 and self in this case is the object receiving the message that happens to define the after/3 event handler as a call to... self. The solution in this case is to use the :/1 control construct (see the manual for details):

Code: Select all

:- category(ctg, implements(monitoring)).

   :- public(test/3).

   test(X, Y, Z) :-
      a(1, X), a(2, Y), a(3, Z).

   after(_, test(X, Y, Z), _) :- !,
      writeq(X), write(' '), writeq(Y), write(' '), writeq(Z), nl.
   after(_, _, _).

   a(1, a).
   a(2, b).
   a(3, c).

:- end_category.


:- object(obj,
   implements(monitoring),
   imports(ctg)).

   :- threaded.
   
   after(Object, Message, Sender) :-
      :after(Object, Message, Sender).

:- end_object.
With this new version of your example you get:

Code: Select all

?- logtalk_load(noel, [events(on)]).  
<<< loading source file noel... 
>>> compiling source file noel...
compiling category ctg... compiled
compiling object obj... compiled
>>> noel source file compiled
% noel.pl compiled 0.01 sec, 5,860 bytes
<<< noel source file loaded
(0 warnings)
true.

?- obj::test(X, Y, Z).              

X = a,
Y = b,
Z = c.

?- define_events(after, _, _, _, obj).
true.

?- obj::test(X, Y, Z).
a b c
X = a,
Y = b,
Z = c.
Cheers,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Tue Apr 08, 2008 12:43 pm

Paulo Moura wrote: The above event handlers will not work as you can only monitor messages sent using the ::/2 control construct; the predicate test/3 is called directly and is thus invisible as far as events areconcerned. In this case, you will need to drop the predicate test1/3 and make test/3 public.
Ok, so I have two choices :
1) use the event but I would be able to use them only for predicates that are called with ::
2) put the debug message in code with a test to see if debug is activated or not

About 1) : It looks like it is not working for predicate owned by a category and called from another category with ::, from a predicate itslef called from the object with :: (See the example I made at the end of the post)

About 2) Do you plan on making a special way to specify code that should only executed when debug is enabled, something like :

Code: Select all

pred(X) :-
    debug((write('Debug : '), writeq(X))),
    a(X).
that would act like a macro in C, that is not compiled if debug is not activated.

Edit : I forgot the example :

Code: Select all

:- category(ctg, extends(ctg2)).

	:- public(test1/3).

	test1(X, Y, Z) :-
		::test(X, Y, Z).

	a(1, a).
	a(2, b).
	a(3, c).

:- end_category.

:- category(ctg2).

	:- public(test/3).

	test(X, Y, Z) :-
		a(1, X), a(2, Y), a(3, Z).

	after(_, test(X, Y, Z), _) :-
		writeq(X), write(' '), writeq(Y), write(' '), writeq(Z), nl.

	a(1, a).
	a(2, b).
	a(3, c).

:- end_category.


:- object(obj,
	implements(monitoring),
	imports(ctg)).

	:- threaded.
	
	after(Object, Message, Sender) :-
	   :after(Object, Message, Sender), !.
	after(_,_,_).

:- end_object.

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

Re: Gorgias port

Post by Paulo Moura » Tue Apr 08, 2008 1:33 pm

Victor NOEL wrote:
Paulo Moura wrote: The above event handlers will not work as you can only monitor messages sent using the ::/2 control construct; the predicate test/3 is called directly and is thus invisible as far as events areconcerned. In this case, you will need to drop the predicate test1/3 and make test/3 public.
Ok, so I have two choices :
1) use the event but I would be able to use them only for predicates that are called with ::
2) put the debug message in code with a test to see if debug is activated or not

About 1) : It looks like it is not working for predicate owned by a category and called from another category with ::, from a predicate itslef called from the object with :: (See the example I made at the end of the post)
Events work for messages sent using the ::/2 control construct, not the ::/1 control construct. Sending a message to "self" is only possible from within an object and, as such, is regarded as something private (events are not meant to break encapsulation).
Victor NOEL wrote:About 2) Do you plan on making a special way to specify code that should only executed when debug is enabled, something like :

Code: Select all

pred(X) :-
    debug((write('Debug : '), writeq(X))),
    a(X).
that would act like a macro in C, that is not compiled if debug is not activated.
It's an interesting suggestion and should be easy to implement. Please consider creating an enhancement ticket with your suggestion at:

http://trac.logtalk.org/

Cheers,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Tue Apr 08, 2008 2:19 pm

I added a ticket for it : http://trac.logtalk.org/ticket/6

Thanks for all you answer :)

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

Re: Gorgias port

Post by Paulo Moura » Tue Apr 08, 2008 7:39 pm

Victor NOEL wrote:I added a ticket for it : http://trac.logtalk.org/ticket/6
Check the ticket. I just commented on it describing an easy solution for the desired functionality using the Logtalk term expansion mechanism.

Best regards,

Paulo

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Thu May 22, 2008 8:07 am

Hello,

I am back again to logtalk and gorgias :)

This time, it is more a logtalk problem, but using gorgias and since I am not sure gorgias is not at fault, I will ask here.

My problem is that I want to be able to create several objects, each with its own database for a set of predicates plus a theory using these predicates, and to use prove from gorgias to reason about them, and that each object is independant from the others.

Since there is a common part with predicates (calling prove) called by the user, I thought about using a class implementing theses predicates, with some method to assert new specific predicates, each object will instantiate this class and will contain some rules for reasoning.

So this is what I did :

Code: Select all

:- object(tharg, imports(gorgias), specializes(logtalk)).

  :- public([update/1, deliberate/2]).
  :- private([stored/1]).
  :- dynamic([stored/1]).
  
  % add a support to the database
  update(E) :-
    assertz(stored(E)).

  % The idea is to prove Goal, but without using a support than has already be stored
  deliberate(Goal, Support) :-
    findall(StoredSupport, stored(StoredSupport), StoredSupportsTmp), sort(StoredSupportsTmp, StoredSupports),
    support(Goal, Support),
    \+ memberchk(Support, StoredSupports).

  % prove the goal, and keep only abducibles
  support(Goal, SupportSet) :-
    ::prove([Goal], Support), 
    filter(is_abducible, Support, FilteredSupport), 
    map(clean_abducible, FilteredSupport, MappedSupport),
    sort(MappedSupport, SupportSet).

  is_abducible(A) :- unifiable(A, ass(_), _).
  clean_abducible(ass(A), A).

  rule(A, B, C) :- .... % here there will be some rules to be used by gorgias
:- end_object.

:- object(buyer, instantiates(tharg)).

  abducible(test).
  rule(r1, buy(low), [test]). % here there is some rules used by gorgias

:- end_object.

:- object(seller, instantiates(tharg)).

  abducible(test2).
  rule(r1, sell(high), [test2]). % here there is some rules used by gorgias

:- end_object.
I put it all, but the important things are the relations between objects, and the fact that there is rules in both.
And I want all the stored/1 to be private to each object instantiating tharg.

When I call prove (The problem is the same if I call deliberate, but the trace is simplier with only prove, this is the trace I get :

Code: Select all

buyer::prove([buy(low)], D).
    Call: buyer::prove([buy(low)], _G186) ?  
    Rule: prove([buy(low)], _G186) ?  
    Call: ::resolve([buy(low)], _G378) ?  
    Fail: ::resolve([buy(low)], _G378) ?  
    Fail: buyer::prove([buy(low)], _G186) ?  
As you can see, the call to resolve just fails without entering it !! I tried to do the same with tharg being a prototype, and buyer extending it, and all work as expected, but if I use instantiation, it doesn't.

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

Re: Gorgias port

Post by Paulo Moura » Thu May 22, 2008 9:13 am

Victor NOEL wrote:

Code: Select all

...
  % add a support to the database
  update(E) :-
    assertz(stored(E)).
...
Above you're asserting the predicate stored/1 within the class, not within the instance (self) that received the original message that resulted in the call to the update/1 predicate. You need to change the definition of update to:

Code: Select all

  update(E) :-
    ::assertz(stored(E)).
Same problem in the definition of the predicate deliberate/2 where you're calling the predicate stored/1 within the class; change the definition to:

Code: Select all

  deliberate(Goal, Support) :-
    findall(StoredSupport, ::stored(StoredSupport), StoredSupportsTmp), sort(StoredSupportsTmp, StoredSupports),
    support(Goal, Support),
    \+ memberchk(Support, StoredSupports).
Victor NOEL wrote: I put it all, but the important things are the relations between objects, and the fact that there is rules in both.
And I want all the stored/1 to be private to each object instantiating tharg.
The changes above should provide you with functionality you need.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Thu May 22, 2008 10:03 am

Ok, I understand for the stored/1 predicate.

But I think there is something strange with the call to the resolve predicate by the gorgias category, when it is called from a class that is instantiated !

If I reduce my example to :

Code: Select all

:- object(tharg, imports(gorgias), specializes(logtalk)).
  :- public([myprove/2]).

  myprove(A, B) :- ::prove(A, B).

:- end_object.

:- object(test, instantiates(tharg)).

  rule(r1, test, []).

:- end_object.
And I call test::myprove :

Code: Select all

test::myprove(test, B).
    Call: test::myprove(test, _G181) ?  
    Rule: myprove(test, _G181) ?  
    Call: ::prove(test, _G181) ?  
    Rule: prove(test, _G181) ?  
    Call: ::resolve(test, _G403) ?  
    Fail: ::resolve(test, _G403) ?  
    Fail: ::prove(test, _G181) ?  
    Fail: test::myprove(test, _G181) ?  
fail.

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

Re: Gorgias port

Post by Paulo Moura » Thu May 22, 2008 11:03 am

Victor NOEL wrote:Ok, I understand for the stored/1 predicate.

But I think there is something strange with the call to the resolve predicate by the gorgias category, when it is called from a class that is instantiated !
You're correct. I'm able to reproduce the problem using a simple example. There is a bug when compiling a class that imports a category that extends other categories. The bug is fixed in the current development version (r4269). Thanks for the bug report.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Fri May 23, 2008 8:04 am

Paulo Moura wrote: You're correct. I'm able to reproduce the problem using a simple example. There is a bug when compiling a class that imports a category that extends other categories. The bug is fixed in the current development version (r4269). Thanks for the bug report.
All is working now :) Thanks you.

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Fri May 23, 2008 9:28 am

Another question :

When I use the inheritance tree described just before (gorgias as a category, imported by a class specializing logtalk, which class is instantiated by several objects).

If I want my class to have a rule/3 defined in its body, to be used by gorgias when proving things from the instantiating object (when I call deliberate/2).

By default, gorgias will not be able to see the rule/3 because it is not contained by the object itself but by the class. If I want it to see it, I can add something like :

Code: Select all

rule(A, B, C) :- ^^rule(A, B, C)
But if I want to avoid using this rules in the object so that the developer of the object does not have to think about it, how can I do ?

Thanks :)

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

Re: Gorgias port

Post by Paulo Moura » Fri May 23, 2008 10:18 am

Victor NOEL wrote: By default, gorgias will not be able to see the rule/3 because it is not contained by the object itself but by the class. If I want it to see it, I can add something like :

Code: Select all

rule(A, B, C) :- ^^rule(A, B, C)
But if I want to avoid using this rules in the object so that the developer of the object does not have to think about it, how can I do ?
Nothing (but check an alternative solution below). I understand that you want to simplify writing objects for the developers that will be using Gorgias but the clause above is both necessary from a programming point-of-view and important as a reminder that the instance rules will be complemented with rules found in the instance ancestors.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Fri May 23, 2008 12:15 pm

Ok, I understand.

Thanks you for all your answers :)

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

Re: Gorgias port

Post by Paulo Moura » Fri May 23, 2008 12:25 pm

Hi Victor!

You could use two different rule predicates, say, default_rule/3, stored usually in classes, and rule/3, stored usually in instances. This would imply modifying the Gorgias code to duplicate clauses that currently use rule/3 to try first rule/3 and, on backtracking, to try default_rule/3. Not sure it's worth the added complexity, though. I prefer to avoid this kind of workarounds and simply rely on the ^^/2 calls.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Victor NOEL
Posts: 48
Joined: Tue May 15, 2007 4:53 pm

Re: Gorgias port

Post by Victor NOEL » Fri May 23, 2008 2:02 pm

Paulo Moura wrote: You could use two different rule predicates, say, default_rule/3, stored usually in classes, and rule/3, stored usually in instances. This would imply modifying the Gorgias code to duplicate clauses that currently use rule/3 to try first rule/3 and, on backtracking, to try default_rule/3
I almost did that :) :
I use my_rule/3 in instances, and in the class I defined all the rule/3 I needed plus :

Code: Select all

rule(A, B, C) :- ::my_rule(A,B,C).
Like that in the instance we just put my_rule/3, and for gorgias all is the same :)

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest