> How do you implement a counter in Prolog?
Like many people who ask "How do I do X in Prolog?" in this newsgroup,
you ask it in such a vague way that it's impossible to give you an answer.
In many cases, if the person would just sit down and think logically about
what they actually want, they would be half way to a Prolog solution.
Matthew Huntbach
/Nygaard
Sent via Deja.com http://www.deja.com/
Before you buy.
> > How do you implement a counter in Prolog?
> Like many people who ask "How do I do X in Prolog?" in this newsgroup,
> you ask it in such a vague way that it's impossible to give you an
> answer.
It does, however, look like he's trying to create an updateable
variable. Which Prolog does not have, period. (Well, there are
workarounds, but DO NOT use them until you've figured out how
to do without them in principle).
The Right solution is to give any procedure which you want to be
able to "update" a value two extra argument: one for the value before
it is executed, and one in which the procedure returns the new value.
And, anticipating a possible follow-up question, DO NOT use a
repeat-fail loop until you know how to program the required behavior
without one.
--
Henning Makholm "They want to be natural, the anti-social
little beasts. They just don't realize that
everyone's good depends on everyone's cooperation."
Turbo/PDC/Visual Prolog syntax is used in the following example. Ellipses (...)
represent program-specific code.
For a list you use 2 variables: one to do the counting, the other to return the
final count.
pred(..., Count, Count).
pred(..., Counter, Count) :-
...,
Counter1 = Counter + 1,
pred(..., Counter1, Count).
In the first clause, which is the terminating (base) one, the last variable (the
final count) binds to the second-from-last one (the counter). As recursion
unwinds the count is passed down to previously unbound Count variables in the
2nd clause (assuming this clause has been called) until it eventually reaches
the original call to the predicate.
A call to this predicate, ie a goal, would be:
...
pred(...,0,Count), % initialize the counter (0 here)
... % process the returned Count
...
You sound like a self-learner. Turbo Prolog is VERY old and has since been
superceded first by PDC Prolog and now Visual Prolog. You can download a free
Visual Prolog from:
Note that Turbo/PDC/Visual Prolog is a fine product, but is somewhat different
from what is widely accepted as the prolog programming language. Visit the
following site to download a free traditional prolog program and a prolog
tutorial:
Have fun!
Daniel
> > > How do you implement a counter in Prolog?
> > Like many people who ask "How do I do X in Prolog?" in this newsgroup,
> > you ask it in such a vague way that it's impossible to give you an
> > answer. In many cases, if the person would just sit down and think logically
> > about what they actually want, they would be half way to a Prolog solution.
> How exactly is this question vague?
Well, all he said was "how do you implement a counter?".
He didn't say what he meant by "a counter". If he were to say, for example,
"How do I count the number of elements in a list?" or "How do I count the
number of times I backtrack to a particular goal?" or "How do I count the
number of facts for this predicate?" or "How do I count the number of
Prolog reductions I make when I execute this goal?" etc etc, it would be
a less vague question, and thus it would be possible to make some suggestions.
> In an other thread you said that you have teaching experience in computer
> languages. This question is normal for students who are used to be presented
> with new languages by example.
Yes, and when you are teaching people, it's very good practice to make them
think about what they actually want to do by questioning them and getting
them to refine their vague thoughts into something more specific.
> I have come to the understanding that you are a genius, and as such you
> feel the right to look down on everybody who does not have the grasp of
> logic you do.
Well, I don't think I've written anything here that suggests I'm a
"genius". I'm trying to get across the message that you don't have to
be a genius to program in Prolog, but you might have to drop some of
the assumptions you have if you are already experienced in programming in
other languages. One way to help people do this is to tease them out to
try and find out what assumptions they might have which are causing them
to make mistakes in Prolog or misunderstand the language.
> I fully accept your right to do this, but could you please
> do it somewhere else. Why not use your genius to help these people to
> better understand prolog.
Why should I bother when if I try to help I'm accused of looking down on
people?
Matthew Huntbach
/Nygaard
In article <7sshg6$68a$1...@beta.qmw.ac.uk>,
In Visual Prolog, you have to define a fact or "database" item first
to help out the compiler. In Visual Prolog can you set up a
FACTS section with a header
that says "FACTS" like this:
FACTS
Then under this heading you might declare a fact like
this:
FACTS
DETERM counter(INTEGER)
Determ, here, tells the compiler that there should be only one counter fact
in the system. This projects you against accidentally having multiple
counter facts.
You might want to initialize the counter to zero
at the beginning of the program, like this:
assert(counter(0))
Then you could create a predicate like this:
add_one_to_counter if
counter(X),
Y = X+1,
retractall(counter(_)),
assert(counter(Y)), !.
add_one_to_counter if
assert(counter(1)), !.
When you want to increment the counter,
just code:
add_one_to_counter,
Whenever you want to know the current counter value,
you just say:
counter(Value),
This will work as long as you have initialized the counter.
If you have not initialized the counter, there is no
count and the above statement will fail.
You could write a predicate to return 0 if there is
no counter fact:
getcounter(X) if
counter(X), !.
getcounter(0) if !.
Yes, it's a lot of work. I guess that's why we avoid counters
in prolog and use other methods for counting things, like
recursion. However, sometimes counters need to
brought to life this way as when we want to use
back tracking rather than recursion.
By the way I am setting up a prolog bookstore on line in association
with Amazon. You may want to take a look.
It's amazing how fast you can have books shipped to you.
You may want to see:
http://www.magicseyer.com/books_on_prolog.htm
-------------------------------------------------------------------
Free Trial! Increase your learning power with MagicBrain. Capture and
organize knowledge; increase your vocabulary; create email reminders; search
the Internet effortlessly, find new friends; order books online; Find Mp3
music files -- Get MagicBrain (tm) -- an intelligent hypertext software
coach for Windows 95/98/NT developed with Visual Prolog Write to
Magic...@SendFree.com -- see http://www.ilovemusic.com/shareware.htm and
http://www.visual-prolog.com/
jc <jjc...@usa.net> wrote in message
news:newscache$p89qif$06l$1...@news.mozcom.com...
> How do you implement a counter in Prolog?
Retract is a slow operation in VIP, and can be avoided for facts such as
counters.
FACTS
SINGLE counter(integer)
CLAUSES /* Initializing facts */
counter(0).
PREDICATES
PROCEDURE incr_counter
CLAUSES /* Rules */
incr_counter :-
counter(X), % get current counter value
Y = X + 1, % default increment is 1
assert(counter(Y)).
GOAL
counter(X),
incr_counter, incr_counter, incr_counter,
counter(Y),
assert(counter(0)), % reset
counter(Z).
/* OUTPUT:
X=0, Y=3, Z=0
1 Solution
*/
Daniel
> FACTS
> SINGLE counter(integer)
> PREDICATES
> PROCEDURE incr_counter
drawback: you fill your memory with counter/1 facts. This would be
called a memory leak in other languages.
--
Gertjan van Noord Alfa-informatica, RUG, Postbus 716, 9700 AS Groningen
vannoord at let dot rug dot nl http://www.let.rug.nl/~vannoord/
No, Gertjan, in this case you are wrong. Here I am using the Visual Prolog mode
qualifier SINGLE, which means that Visual Prolog will maintain one, and only one
instance of the counter/1 fact. Thus the absence of any calls to the built-in
retract/1 predicate.
You may have noticed that my message was posted as a reply to Tango's message,
which contained a poor example of implementing counters using the internal
database (in Visual Prolog).
Daniel
>Daniel Dudley (dud...@online.no) wrote:
>> Retract is a slow operation in VIP, and can be avoided for facts such as
>> counters.
>
>> FACTS
>> SINGLE counter(integer)
...
>> CLAUSES /* Rules */
>> incr_counter :-
>> counter(X), % get current counter value
>> Y = X + 1, % default increment is 1
>> assert(counter(Y)).
>
>drawback: you fill your memory with counter/1 facts. This would be
>called a memory leak in other languages.
No, I think that in VIP the "SINGLE" keyword here changes the semantics
of assert/1 when used on that procedure, so there is no memory leak.
assert/1 in this VIP example is like a combination of retract/1 and
assert/1 in standard Prolog. (Yet another example, of course,
of how VIP differs from standard Prolog...)
--
Fergus Henderson <f...@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger f...@128.250.37.3 | -- the last words of T. S. Garp.
ok, I stand corrected.
--
-------------------------------------------------------------------
Free Trial! Increase your learning power with MagicBrain. Capture and
organize knowledge; increase your vocabulary; create email reminders; search
the Internet effortlessly, find new friends; order books online; Find Mp3
music files -- Get MagicBrain (tm) -- an intelligent hypertext software
coach for Windows 95/98/NT developed with Visual Prolog Write to
Magic...@SendFree.com -- see http://www.ilovemusic.com/shareware.htm and
http://www.visual-prolog.com/
Daniel Dudley <dud...@online.no> wrote in message
news:ZgxI3.1122$ZF4....@news1.online.no...
> Tango <Ta...@ilovemusic.com> wrote in message
> news:37f28a88$0$2...@nntp1.ba.best.com...
> > You can bring a counter to life with assert and retract.
>
> Retract is a slow operation in VIP, and can be avoided for facts such as
> counters.
>
> FACTS
> SINGLE counter(integer)
>
> CLAUSES /* Initializing facts */
> counter(0).
>
> PREDICATES
> PROCEDURE incr_counter
>
> CLAUSES /* Rules */
> incr_counter :-
> counter(X), % get current counter value
> Y = X + 1, % default increment is 1
> assert(counter(Y)).
>
> GOAL
> counter(X),
> incr_counter, incr_counter, incr_counter,
> counter(Y),
> assert(counter(0)), % reset
> counter(Z).
>
> /* OUTPUT:
> X=0, Y=3, Z=0
> 1 Solution
> */
>
> Daniel
>
>
I didn't know about the SINGLE qualifier.
Wow, I can save a lot of retracts!
I'm glad Dudley is around to keep us on our toes.
(even if he is a bit brusque at times) :)
---------------------------------------------------------------------
Here's the VIP documentaiton on "single" for those who might be interested:
Facts declared with the keyword single.
The keyword single before a fact fact_N declaration determines that one and
only one instance of a fact must always exist:
· Since single facts must be already known when the program calls Goal;
therefore, single facts must be initialized in a clauses section in the
program's source code. For example:
FACTS
single singleFact(STRING, STRING)
CLAUSES
singleFact("","").
· Single facts cannot be retracted. If one try to apply any retract
predicate to a single fact then the compiler will generates the error 249
"Attempt to retract a fact declared as single".
· Since one instance of a single fact always exists, a single fact never
fails if it is called with free arguments. For example, a following call
singleFact(X,Y),
never fails if X and Y are free variables. Therefore, it is convenient to
use single facts in procedures.
· assert, asserta, assertz, and consult predicates applied to a single fact
act similarly to couples of retract and assert predicates. That is, assert
(consult) predicates change the existing instance of a fact to the specified
one.
· Preceding a fact with single enables the compiler to produce optimized
code for accessing and updating of a fact. For example, for assert predicate
applied to a single fact the compiler generates a code that works more
effectively that a couple of retract and assert predicates applied to a
determ fact (and all the more so then retract and assert predicates applied
to a nondeterm fact).
-------------------------------------------------------------------
MagicBrain now facilitates automatic uploads to ftp sites.
Free Trial! Increase your learning power with MagicBrain. Capture and
organize knowledge; increase your vocabulary; create email reminders; search
the Internet effortlessly, find new friends; order books online; Find Mp3
music files -- Get MagicBrain (tm) -- an intelligent hypertext software
coach for Windows 95/98/NT developed with Visual Prolog Write to
Magic...@SendFree.com -- see http://www.ilovemusic.com/shareware.htm and
http://www.visual-prolog.com/
Daniel Dudley <dud...@online.no> wrote in message
news:MbNI3.1617$ZF4....@news1.online.no...
> Noord G.J.M. van <vann...@let.rug.nl> wrote in message
> news:7sv0om$ga4$1...@syn.let.rug.nl...
> > Daniel Dudley (dud...@online.no) wrote:
> > drawback: you fill your memory with counter/1 facts. This would be
> > called a memory leak in other languages.
>
> No, Gertjan, in this case you are wrong. Here I am using the Visual Prolog
mode
> qualifier SINGLE, which means that Visual Prolog will maintain one, and
only one
> instance of the counter/1 fact. Thus the absence of any calls to the
built-in
> retract/1 predicate.
>
If your "Prolog" has global variables, then they would be a better
option because they are faster.
IMHO, routine use of assert/retract/global vars is (a) very bad
programming style, and (b) can (and therefore should) be avoided in this
example. I'm certainly no purist, but beginners should learn how to
program Prolog "properly" first!
Here's one way:
start(0).
increment(A, B) :- B is A + 1.
decrement(A, B) :- B is A - 1.
e.g. a counter on a list:
length([], C) :- start(C).
length([_|T], C2) :- length(T, C1), increment(C1, C2).
e.g. sum the length of two lists:
count([], C, C).
count([_|T], C1, C3) :- increment(C1,C2), count(T,C2,C3).
count_lists(L1, L2, C2) :-
start(C0), count(L1, C0, C1), count(L2, C1, C2).
The important point in these examples is that there's no such thing as
global state. The counter is passed around in local variables.
--
Calum Grant
You bet.
> However, there is a danger
> that if backtracking is needed all of the different values of
> the counter that have been asserted will be retrieved and
> that is probably not what you want. That's why I like
> to use DETERMINISTIC counter facts, that is there is only
> allowed to be once such fact in the system.
What a load of rubbish!
There is but one counter/1 fact when the mode qualifier SINGLE is used and
backtracking will never occur because no choice points are set. Note that a
SINGLE fact must always exist, which in practice requires that it must be
hard-coded before compilation.
Similarly, use of the mode qualifier DETERM on a fact stipulates that only one
such fact will be present in the internal database. However, unlike a SINGLE
fact, attempts to assert a new fact without first retracting the current one
will result in an error. Also here there are no choice points set, so a cut (!)
after the nondeterministic retract/1 or retract/2 is redundant. (Note that your
code is a frightening example of misplaced cuts!)
(spam snipped - not only is this not welcome, it is illegal! If you continue to
use the pretext of a reply/replic - bad ones at that - to spam the newsgroup,
I'll get you banned from the news server. You have been warned!)
(message news:ZgxI3.1122$ZF4....@news1.online.no snipped)
Daniel
You're welcome.
> I didn't know about the SINGLE qualifier.
> Wow, I can save a lot of retracts!
And a lot of cuts!
> I'm glad Dudley is around to keep us on our toes.
> (even if he is a bit brusque at times) :)
Sometimes it's needed.
(snipped: VIP documentaiton on "single")
(spam snipped - not only is this not welcome, it is illegal! If you continue to
use the pretext of a reply/replic - bad ones at that - to spam the newsgroup,
I'll get you banned from the news server. You have been warned!)
(message news:MbNI3.1617$ZF4....@news1.online.no snipped)
Daniel