Using a counter in Logtalk+SWI-Prolog

Help requests on developing Logtalk applications

Moderator: Paulo Moura

Post Reply
Monikuta
Posts: 13
Joined: Mon May 12, 2008 9:02 am

Using a counter in Logtalk+SWI-Prolog

Post by Monikuta » Tue May 27, 2008 6:46 pm

Hello, i want to use a counter for drawing the board of my Checkers game.
I am using Logtalk having SWI-Prolog as the back-end Prolog compiler.
I tried in two ways, but I received some errors and did not manage to eliminate them.

First attempt:

Code: Select all

:-object(board,
             instantiates(class),
             specializes(object)).

:-public(init/0).

:- public(counter/1).
:- dynamic(counter/1).

init:- retractall(counter(_)),
         assert(counter(7)).

...
:- end_object.
and I got the error
ERROR: toplevel: Undefined procedure: counter/1 (DWIM could not correct goal)

Second attempt:

Code: Select all

:-object(board,
             instantiates(class),
             specializes(object)).
  
  :- public(loadCounter/0).
  :- public(init/0).
 
  loadCounter :- consult('counter.pl').  % in counter.pl I have a single line: counter(0).

   init :- retractall(counter(_)),
             assert(counter(7)).
   ...
:- end_object.


gives me the error
WARNING! This predicate is called but never defined: counter/1
Could you please tell me what am I doing wrong?
Thank you very much,
Monica Dogaru

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

Re: Using a counter in Logtalk+SWI-Prolog

Post by Paulo Moura » Tue May 27, 2008 7:23 pm

Monikuta wrote: Hello, i want to use a counter for drawing the board of my Checkers game.
I am using Logtalk having SWI-Prolog as the back-end Prolog compiler.
I tried in two ways, but I received some errors and did not manage to eliminate them.

First attempt:

Code: Select all

:-object(board,
             instantiates(class),
             specializes(object)).

:-public(init/0).

:- public(counter/1).
:- dynamic(counter/1).

init:- retractall(counter(_)),
         assert(counter(7)).

...
:- end_object.
and I got the error
ERROR: toplevel: Undefined procedure: counter/1 (DWIM could not correct goal)
Assuming that you're using the "class" and "object" objects defined in the Logtalk "roots" example, your "board" object will play the role of a(n instantiable) class. How are you using this class? What query are you typing at the top-level that results in the error you describe above?

Try the following at the top-level (after loading the "roots" example and the class "board"):

Code: Select all

|?- board::new(Board), Board::counter(Counter).
The definition of the predicate init/0 is probably not what you want. If your intent is to have "board" instances, each one with its own counter value, then you need to write:

Code: Select all

init :-
    ::retractall(counter(_)),
    ::asserta(counter(7)).
Don't use assert/1; it's not a(n ISO) standard built-in predicate and it's not a Logtalk database built-in method. The ::/1 control construct used in this second version of the init/1 predicate means that you're sending the retractall/1 and asserta/1 messages to self, i.e. to the object (a "board" instance) that received the init/1 message. As a consequence, you will be retracting and asserting clauses for counter/1 in the instance itself. Your original definition of the predicate init/1 retracted and asserted a clause for the dynamic predicate counter/1 in the class itself (which, btw, it's the standard way of implementing shared instance variables).
Monikuta wrote: Second attempt:

Code: Select all

:-object(board,
             instantiates(class),
             specializes(object)).
  
  :- public(loadCounter/0).
  :- public(init/0).
 
  loadCounter :- consult('counter.pl').  % in counter.pl I have a single line: counter(0).

   init :- retractall(counter(_)),
             assert(counter(7)).
   ...
:- end_object.


gives me the error
WARNING! This predicate is called but never defined: counter/1
Could you please tell me what am I doing wrong?
If you want to define an initial value for the counter/1 predicate, just add the clause "counter(0)." to the code of the "board" class. This clause would be inherited by all instances. Instances would get their own, local values after you send them the init/1 message. Your use of the consult/1 predicate just loads the contents of the "counter.pl" file into the Prolog database (or, from the Logtalk point-of-view, into the pseudo-object user that virtually contains all the Prolog code not encapsulated in some Logtalk entity or Prolog module).

Best regards,

Paulo
Paulo Moura
Logtalk developer

Monikuta
Posts: 13
Joined: Mon May 12, 2008 9:02 am

Re: Using a counter in Logtalk+SWI-Prolog

Post by Monikuta » Tue May 27, 2008 7:37 pm

I tried modifying the code from the first attempt:

Code: Select all

:- public(counter/1).
  :- dynamic(counter/1).
 
  init :- 
          ::retractall(counter(_)),
          ::asserta(counter(7)).

   countup :-
              init,       
              counter(Count),	
              ::retractall(counter(Count)),	
              Newcount is Count - 1,	
              ::asserta(counter(Newcount)). 

    makeBoard([White,Red,_]):- 
	                        init, ...
then I execute the queries:
?- {roots(loader), board}.
?- board::new(B, [white-([0/0,0/2,1/1,2/0,2/2,3/1,4/0,4/2,5/1,6/0,6/2,7/1]), red-([0/6,1/7,1/5,2/6,3/7,3/5,4/6,5/7,5/5,6/6,7/7,7/5]), piece-(white)]), B::counter(C).

and it gives me "fail". :(

Shouldn't the predicate "counter" also be defined inside the class board, not just declared?
Thank you,
Monica Dogaru

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

Re: Using a counter in Logtalk+SWI-Prolog

Post by Paulo Moura » Tue May 27, 2008 10:37 pm

Hi,

try the following definition for the countup/0 predicate:

Code: Select all

countup :-
    init,
    ::retract(counter(Count)),
    Newcount is Count - 1,
    ::asserta(counter(Newcount)).
Note that in your original definition you're calling the predicate counter/1 in the class. Predicate calls that do not use one of the message sending operators are compiled as calls to local predicates (unless they correspond to built-in predicates, of course).
Monikuta wrote: then I execute the queries:
?- {roots(loader), board}.
?- board::new(B, [white-([0/0,0/2,1/1,2/0,2/2,3/1,4/0,4/2,5/1,6/0,6/2,7/1]), red-([0/6,1/7,1/5,2/6,3/7,3/5,4/6,5/7,5/5,6/6,7/7,7/5]), piece-(white)]), B::counter(C).

and it gives me "fail". :(

Shouldn't the predicate "counter" also be defined inside the class board, not just declared?
Classes declare predicates for their descendant instances. Classes, as I explained in my previous post, may also define default values for those predicates. In your case, there should be a initial, default definition for the predicate counter/1 in the class, otherwise the retract/1 message will just fail.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Monikuta
Posts: 13
Joined: Mon May 12, 2008 9:02 am

Re: Using a counter in Logtalk+SWI-Prolog

Post by Monikuta » Wed May 28, 2008 6:04 am

Hello,
thank you very much for your prompt answer, I found it very helpful.
This problem is solved and it works fine.

But, what should I do if I need to have a call for the counter method inside
my sorting algorithm? I tried several ways, but did not succeed :(

Code: Select all

sortingAlgorithm(In,Out,End):-
	                   counter(Count),      % here is my problem
	                   getRow(Count,In,[],Row,Rest),
	                   sort(Row,SortedRow),
	                   append(Out,SortedRow,NewOut),
	                   countup,
	                   sortingAlgorithm(Rest,NewOut,End).
Thank you in advance,
Monica Dogaru

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

Re: Using a counter in Logtalk+SWI-Prolog

Post by Paulo Moura » Wed May 28, 2008 7:51 am

Monikuta wrote: But, what should I do if I need to have a call for the counter method inside
my sorting algorithm? I tried several ways, but did not succeed :(
...
Simply write "::counter(Count)" instead of "counter(Count)". I.e. call the counter/1 predicate in self, not in the class.

Best regards,

Paulo
Paulo Moura
Logtalk developer

Monikuta
Posts: 13
Joined: Mon May 12, 2008 9:02 am

Re: Using a counter in Logtalk+SWI-Prolog

Post by Monikuta » Wed May 28, 2008 3:16 pm

Thank you very much for your help, I greatly appreciate it. I had some other bug, and I thought it had to do with "counter". But it was someting else...got rid of it, now it's ok :)
I will come back with details or questions.
Thanks again!
Yours sincerely,
Monica Dogaru

Post Reply

Who is online

Users browsing this forum: No registered users and 2 guests