Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

prolog challenge problem

104 views
Skip to first unread message

johannes falcone

unread,
Jan 7, 2015, 2:02:28 AM1/7/15
to
count from 1 to 100
if the number is divisible by 3 print foo
if by 5 print bar
if by 3 and 5 print foobar
if not either, print the number itself

post your swi prolog or other prolog solution!

I am curious how close the prolog code looks to a executible problem definiton...

Paul Sephton

unread,
Jan 12, 2015, 1:39:38 AM1/12/15
to
Sounds rather like a homework problem. Ok, I'll bite.

%______________________________________________________________________
% divisable(A, B) if either A or B are zero
divisable(0, _) :- write('foo'), fail.
divisable(_, 0) :- write('bar').
divisable(0, _).

% X is divisable if the X modulus 3 or 5 is zero
divisable(X) :-
A is X mod 3, B is X mod 5, divisable(A, B).

% For X between 1 and 100 inclusive, write the number if not divisable
counter :-
between(1,100,X),
( not(divisable(X)) -> write(X), write(' ');
write(' ')
),
fail.
counter :- nl.

%__________________________________________________________

The prolog logic exactly mirrors your problem definition. You state the problem, not it's solution. The solution is found by proving your goal.

johannes falcone

unread,
Jan 22, 2015, 10:26:47 PM1/22/15
to
awesome!!

I was talking to my dad who knows c and fortran and his job was to write specifications that would then be 'coded up' by the 'software lab'.
He said much the same, he expressed the logic of what he wanted.

is that code runnable in swi prolog?

I might try it.

johannes falcone

unread,
Jan 23, 2015, 1:24:13 AM1/23/15
to
On Monday, January 12, 2015 at 1:39:38 AM UTC-5, Paul Sephton wrote:
What parts are code and what statements in your solution? The % throws me off.

Paul Sephton

unread,
Jan 23, 2015, 2:08:09 AM1/23/15
to
The code is tunnable in SWI prolog (and compatible with most others). Everything after a '%' is a comment.

When you run swipl, it brings up a ?- prompt. Executing the goal produces:

?- counter.
1 2 foo 4 bar foo 7 8 foo bar 11 foo 13 14 foobar 16 17 foo 19 bar foo 22 23 foo bar 26 foo 28 29 foobar 31 32 foo 34 bar foo 37 38 foo bar 41 foo 43 44 foobar 46 47 foo 49 bar foo 52 53 foo bar 56 foo 58 59 foobar 61 62 foo 64 bar foo 67 68 foo bar 71 foo 73 74 foobar 76 77 foo 79 bar foo 82 83 foo bar 86 foo 88 89 foobar 91 92 foo 94 bar foo 97 98 foo bar
true.

Have fun.

Paul Sephton

unread,
Jan 23, 2015, 2:53:30 AM1/23/15
to
On Friday, 23 January 2015 08:24:13 UTC+2, johannes falcone wrote:
> What parts are code and what statements in your solution? The % throws me off.

If you are having trouble deciphering the logic, take a look at the following. I have expanded and commented the predicates to make them more understandable. Note that Prolog tries to prove the goal (counter) that you give it. If a particular rule fails, it tries the next rule. This is called backtracking.

Take for example write_number_if_not_divisable/1; this predicate always fails, which causes the place where it was called (in counter/0) to fail also, making Prolog backtrack to try the the next number generated by between/3.

%_____________________________________________________________________________
divisable(0, _) :- write('foo'), fail. % write 'foo' if A and retry goal
divisable(_, 0) :- write('bar'). % succeed and write 'bar' if B
divisable(0, _). % succeed if A

divisable(X) :-
A is X mod 3, B is X mod 5, % Calc modulus and
divisable(A, B). % prove divisable goal

write_number_if_not_divisable(X) :-
not(divisable(X)), write(X), fail. % if not divisable write number, retry
write_number_if_not_divisable(_) :- % write space and fail goal
write(' '), fail.

counter :-
between(1,100,X),
write_number_if_not_divisable(X).
counter :- nl.

johannes falcone

unread,
Jan 25, 2015, 3:59:16 AM1/25/15
to
$ swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.6.6)
Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.

For help, use ?- help(Topic). or ?- apropos(Word).

?- ['/home/g/prolog/fizzbuzz'].
% /home/g/prolog/fizzbuzz compiled 0.00 sec, 7 clauses
true.

?- counter.
1 2 foo 4 bar foo 7 8 foo bar 11 foo 13 14 foobar 16 17 foo 19 bar foo 22 23 foo bar 26 foo 28 29 foobar 31 32 foo 34 bar foo 37 38 foo bar 41 foo 43 44 foobar 46 47 foo 49 bar foo 52 53 foo bar 56 foo 58 59 foobar 61 62 foo 64 bar foo 67 68 foo bar 71 foo 73 74 foobar 76 77 foo 79 bar foo 82 83 foo bar 86 foo 88 89 foobar 91 92 foo 94 bar foo 97 98 foo bar
true.



awesome!!!!!

working code!

I was foolishly trying to type in the code line by line.

Prolog kicks ass!

johannes falcone

unread,
Jan 25, 2015, 4:14:35 AM1/25/15
to
What is the counter :- nl. doing?
How would I modify this to make one entry, then newline?

johannes falcone

unread,
Jan 25, 2015, 4:24:59 AM1/25/15
to
I saw nl is new line, but the program prints out all results in 1 long line...is why I ask..

Paul Sephton

unread,
Jan 26, 2015, 1:29:41 AM1/26/15
to
If you look at the first clause of the counter/0 predicate, you will see that there is no way for it to succeed. It will always fail after backtracking to all of the possible solutions.
The second clause of counter/0 adds a newline to the end of whatever has already been output, and succeeds. So the second clause only gets executed once.
Swipl has a debug mode which allows you to trace execution. This will be really useful to you in figuring out how the example is working. To use it, simply add the line
trace,
to the first line of the first clause of the counter/0 predicate. Also, from the swipl prompt, use
?- help(trace).
This should tell you all about tracing the code.
Good luck.

johannes falcone

unread,
Jan 29, 2015, 7:35:00 PM1/29/15
to
Ok let me try and talk through this:

% divisable(A, B) if either A or B are zero


divisable(0, _) :- write('foo'), fail.
% so this says if A is divisible by zero, write foo? I thought the thing to the
% right of the :- was checked first in prolog..
divisable(_, 0) :- write('bar').
% here B is checked, and writes bar, and foobar is written is the A check above worked?
divisable(0, _).
% why call divisable again? so that foo alone can be output I'm guessing?

R Kym Horsell

unread,
Jan 29, 2015, 8:20:27 PM1/29/15
to
Paul Sephton <prse...@gmail.com> wrote:

You drank the potion so now for it's time for the warning(*):

<www.youtube.com/watch?v=ZL4IVbhai7I>

> On Sunday, 25 January 2015 11:24:59 UTC+2, johannes falcone wrote:
>...


(*) Don't blame me. We've been doing it this way for 947 galactic rotations.

--
The good news: there has been a dramatic increase in Arctic sea ice.
The bad: it's still half the level is was in the 1980s
-- The Independent, 16 Dec 2013

Paul Sephton

unread,
Jan 30, 2015, 1:50:23 AM1/30/15
to
In the code, divisable/2 is a predicate with three rules.
In prolog, a rule can either succeed or fail. If a rule fails, the engine will try the next rule to try and prove the predicate.

Rule 1 for predicate divisable(A,B):
divisable(0, _) :- write('foo'), fail.
matches if the first argument (A) is bound to the value 0. If it matches, it writes 'foo' and then the rule fails. So this rule always fails.

Rule 2 for predicate diviable(A,B):
divisable(_, 0) :- write('bar').
matches if the second argument, B, is bound to the value 0. If it matches, the rule writes the string 'bar' and succeeds.

Rule 3:
divisable(0, _).
matches if the first argument can be bound to 0, and succeeds. This rule is here because rule 1 always fails, and we want to succeed for A =:= 0.


So, for the predicate divisable/2, we can write:

A B output result
- - nothing fail
0 - foo succeed (rule 3)
- 0 bar succeed (rule 2)
0 0 foobar succeed (rule 2 or 3)

If the predicate divisable/2 fails, we know we must write the number instead. If it succeeds, we know we must not write a number, and the appropriate text has already been output.

For A=0, B=0, rule 1 matches, outputs foo, fails, then rule 2 matches outputs bar succeeeds, so we get foobar.

Have fun

johannes falcone

unread,
Jan 31, 2015, 12:22:44 PM1/31/15
to
Awesome!
Wow prolog really seems powerful.
I final question[of course] what does A =:= 0 mean?

Paul Sephton

unread,
Feb 2, 2015, 1:54:31 AM2/2/15
to
From the swi prolog manual (type help. at the prompt), under the section Arithmetic, General Purpose Arithmetic, you will find:

+Expr1 > +Expr2 [ISO]
True if expression Expr1 evaluates to a larger number than Expr2.


+Expr1 < +Expr2 [ISO]
True if expression Expr1 evaluates to a smaller number than Expr2.


+Expr1 =< +Expr2 [ISO]
True if expression Expr1 evaluates to a smaller or equal number to
Expr2.


+Expr1 >= +Expr2 [ISO]
True if expression Expr1 evaluates to a larger or equal number to
Expr2.


+Expr1 =\= +Expr2 [ISO]
True if expression Expr1 evaluates to a number non-equal to Expr2.


+Expr1 =:= +Expr2 [ISO]
True if expression Expr1 evaluates to a number equal to Expr2.


-Number is +Expr [ISO]
True when Number is the value to which Expr evaluates. Typically,
is/2 should be used with unbound left operand. If equality is to
be tested, =:=/2 should be used. For example:

?- 1 is sin(pi/2). Fails!. sin(pi/2) evaluates
to the float 1.0, which does
not unify with the integer 1.
?- 1 =:= sin(pi/2). Succeeds as expected.

Now, I know your next question will be: Where is equals (=)?

Well, its there too, but you read X = Y as "X is bound to Y". Such a test does not test arithmetic equivalence, but atomic equivalence.

eg. X=abc, Y=abc, X = Y. will succeed, while
X=123, Y=123, X = Y will also, but
X=123.0, Y=123, X = Y will not.

Kind regards
0 new messages