prolog - why this strange trace - logic

here is the prolog code (which i sort of follow).
len([],0).
len([_|T],N) :- len(T,X), N is X+1.
and here is the trace for it (im running linux, swi)
[trace] ?- len([d,f,w,c],X).
Call: (7) len([d, f, w, c], _G314) ?
Call: (8) len([f, w, c], _L182) ?
Call: (9) len([w, c], _L201) ?
Call: (10) len([c], _L220) ?
Call: (11) len([], _L239) ?
Exit: (11) len([], 0) ?
^ Call: (11) _L220 is 0+1 ?
^ Exit: (11) 1 is 0+1 ?
Exit: (10) len([c], 1) ?
^ Call: (10) _L201 is 1+1 ?
^ Exit: (10) 2 is 1+1 ?
Exit: (9) len([w, c], 2) ?
^ Call: (9) _L182 is 2+1 ?
^ Exit: (9) 3 is 2+1 ?
Exit: (8) len([f, w, c], 3) ?
^ Call: (8) _G314 is 3+1 ?
^ Exit: (8) 4 is 3+1 ?
Exit: (7) len([d, f, w, c], 4) ?
X = 4.
i know prolog runs down these 'trees' but im having trouble figuring out why the increment to the variable is only done when it is exiting - any explainations of the mechanics of this?
Many thanks!

The reason for this, is that N is X+1 is the last part to the predicate.
Think of it like this: to calculate N is X+1, we need to know the value of X, which is calculated by calling len(T,X). But the process of calculating X requires yet another call to len, all the way to the situation where you end up with an empty list.
It is at that point that the list length is known, namely 0. Thus that value is "returned". Only then 0 + 1 can calculated and "returned". And then 1 + 1. Etc.
Thinking of it another way, observe that for any two predicates a and b, a, b yields true iff both a and b are true. In Prolog, b will only be evaluated if it is known that a is true (otherwise there is no point in evaluating b, since the result is known to be false).
As a result, all additions are done after the recursive calls to len.

Related

Prolog reverse lookup and input validation at the same time

I have started learning prolog recently and even though it is refreshing to move away from functional programming, things still seem very foreign. I having trouble understanding how I can write a predicate that checks whether its argument adhere to a certain set of rules and also at the same time if given a variable will set it to the possible values that satisfy those rules.
I was trying to solve the circular table seating problem where you define a set of conditions for people to sit next to each other. So the knowledge base contains 10 individuals with the languages they speak and the goal is to seat them in a way such that two people sitting next to each other must speak the same language.
I defined a predicate speaks_same(X, Y) which returns true if both individuals X and Y speak the same language. Now the goal is to write a function table_seating such that table_seating([mark, carl, emily, kevin, oliver]) returns true if each two people sitting next to each other in the list speak a common language. Of course for this to happen each person must speak more than one language. And also table_seating(L). would produce the possible table seatings that satisfy the condition.
The way I see it is I can either write a predicate that checks if a previously defined list satisfies the rules or one the builds a list according to these rules. I don't understand how I can do both with one function.
Any help would be really appreciated, thanks!
I don't understand how I can do both with one function.
Yes, at first this seems odd, but then once you get the hang of it, you miss it in other languages.
The word you want to remember when referencing this is: mode
Also see Mercury Modes reference for more detail related to the Mercury programming language.
In Prolog an argument can be an input, and output, or both used as an input or output depending upon how it is called.
In Type, mode and determinism declaration headers at the bottom is listed 4 examples.
length(+List:list, -Length:int) is det.
length(?List:list, -Length:int) is nondet.
length(?List:list, +Length:int) is det.
True if List is a list of length Length.
and the definition of length/2 shows
length(?List, ?Int)
meaning
that for the List argument, the list can be bound or unbound, and
that for the Int argument, the value can be bound or unbound.
So for the two arguments with two options there are four ways to use length/2
Here they are listed again but in actual usage.
1.
length(+List:list, -Length:int) is det.
in this case List is bound and Length is unbound and always gives one answer.
?- length([1,2,3],N).
N = 3.
2.
length(?List:list, -Length:int) is nondet.
in this case List is unbound and Length is unbound and can return any number of answers.
?- length(List,N).
List = [],
N = 0 ;
List = [_5362],
N = 1 ;
List = [_5362, _5368],
N = 2 ;
List = [_5362, _5368, _5374],
N = 3 ;
List = [_5362, _5368, _5374, _5380],
N = 4 ;
List = [_5362, _5368, _5374, _5380, _5386],
N = 5
...
3.
length(?List:list, +Length:int) is det.
in this case List is unbound and Length is bound and always gives one answer.
?- length(List,4).
List = [_5332, _5338, _5344, _5350].
4.
True if List is a list of length Length.
in this case List is bound and Length is bound and always acts as predicate to return either true or false.
?- length([1,2,3],3).
true.
?- length([1,2,3],5).
false.
So how is this possible?
Prolog uses syntactic unification (↦) and NOT assignment (=).
If we look at the source code for length/2 using listing/1 we get
?- listing(length/2).
system:length(B, A) :-
var(A), !,
'$skip_list'(D, B, C),
( C==[]
-> A=D
; var(C)
-> C\==A,
'$length3'(C, A, D)
; throw(error(type_error(list, B), context(length/2, _)))
).
system:length(B, A) :-
integer(A),
A>=0, !,
'$skip_list'(D, B, C),
( C==[]
-> A=D
; var(C)
-> E is A-D,
'$length'(C, E)
; throw(error(type_error(list, B), context(length/2, _)))
).
system:length(_, A) :-
integer(A), !,
throw(error(domain_error(not_less_than_zero, A),
context(length/2, _))).
system:length(_, A) :-
throw(error(type_error(integer, A), context(length/2, _))).
which is too much detail but does do all 4 modes correctly.
To make it easier to understand we will use this version, but it doesn't support 1 of the modes correctly but it does do more than one mode so it works good enough to demonstrate.
length_2([] , 0 ).
length_2([_|Xs] , L ) :-
length_2(Xs,N),
L is N+1 .
Now to see the unification in action we will use the trace feature of SWI-Prolog and to enable all of the ports for the box model use visible/1 and so as not to stop it when running use leash/1.
?- visible(+all),leash(-all).
?- trace.
1.
[trace] ?- length_2([1,2,3],N).
Call: (8) length_2([1, 2, 3], _2352)
Unify: (8) length_2([1, 2, 3], _2352)
Call: (9) length_2([2, 3], _2580)
Unify: (9) length_2([2, 3], _2580)
Call: (10) length_2([3], _2580)
Unify: (10) length_2([3], _2580)
Call: (11) length_2([], _2580)
Unify: (11) length_2([], 0)
Exit: (11) length_2([], 0)
Call: (11) _2584 is 0+1
Exit: (11) 1 is 0+1
Exit: (10) length_2([3], 1)
Call: (10) _2590 is 1+1
Exit: (10) 2 is 1+1
Exit: (9) length_2([2, 3], 2)
Call: (9) _2352 is 2+1
Exit: (9) 3 is 2+1
Exit: (8) length_2([1, 2, 3], 3)
N = 3.
2.
[trace] ?- length_2(List,N).
Call: (8) length_2(_2296, _2298)
Unify: (8) length_2([], 0)
Exit: (8) length_2([], 0)
List = [],
N = 0 ;
Redo: (8) length_2(_2296, _2298)
Unify: (8) length_2([_2528|_2530], _2298)
Call: (9) length_2(_2530, _2550)
Unify: (9) length_2([], 0)
Exit: (9) length_2([], 0)
Call: (9) _2298 is 0+1
Exit: (9) 1 is 0+1
Exit: (8) length_2([_2528], 1)
List = [_2528],
N = 1 ;
Redo: (9) length_2(_2530, _2550)
Unify: (9) length_2([_2534|_2536], _2556)
Call: (10) length_2(_2536, _2556)
Unify: (10) length_2([], 0)
Exit: (10) length_2([], 0)
Call: (10) _2560 is 0+1
Exit: (10) 1 is 0+1
Exit: (9) length_2([_2534], 1)
Call: (9) _2298 is 1+1
Exit: (9) 2 is 1+1
Exit: (8) length_2([_2528, _2534], 2)
List = [_2528, _2534],
N = 2 ;
Redo: (10) length_2(_2536, _2556)
Unify: (10) length_2([_2540|_2542], _2562)
Call: (11) length_2(_2542, _2562)
Unify: (11) length_2([], 0)
Exit: (11) length_2([], 0)
Call: (11) _2566 is 0+1
Exit: (11) 1 is 0+1
Exit: (10) length_2([_2540], 1)
Call: (10) _2572 is 1+1
Exit: (10) 2 is 1+1
Exit: (9) length_2([_2534, _2540], 2)
Call: (9) _2298 is 2+1
Exit: (9) 3 is 2+1
Exit: (8) length_2([_2528, _2534, _2540], 3)
List = [_2528, _2534, _2540],
N = 3
3.
[trace] ?- length_2(List,3).
Call: (8) length_2(_5534, 3)
Unify: (8) length_2([_5724|_5726], 3)
Call: (9) length_2(_5726, _5746)
Unify: (9) length_2([], 0)
Exit: (9) length_2([], 0)
Call: (9) 3 is 0+1
Fail: (9) 3 is 0+1
Redo: (9) length_2(_5726, _5746)
Unify: (9) length_2([_5730|_5732], _5752)
Call: (10) length_2(_5732, _5752)
Unify: (10) length_2([], 0)
Exit: (10) length_2([], 0)
Call: (10) _5756 is 0+1
Exit: (10) 1 is 0+1
Exit: (9) length_2([_5730], 1)
Call: (9) 3 is 1+1
Fail: (9) 3 is 1+1
Redo: (10) length_2(_5732, _5752)
Unify: (10) length_2([_5736|_5738], _5758)
Call: (11) length_2(_5738, _5758)
Unify: (11) length_2([], 0)
Exit: (11) length_2([], 0)
Call: (11) _5762 is 0+1
Exit: (11) 1 is 0+1
Exit: (10) length_2([_5736], 1)
Call: (10) _5768 is 1+1
Exit: (10) 2 is 1+1
Exit: (9) length_2([_5730, _5736], 2)
Call: (9) 3 is 2+1
Exit: (9) 3 is 2+1
Exit: (8) length_2([_5724, _5730, _5736], 3)
List = [_5724, _5730, _5736]
Action (h for help) ? abort
% Execution Aborted
4.
[trace] ?- length_2([1,2,3],3).
Call: (8) length_2([1, 2, 3], 3)
Unify: (8) length_2([1, 2, 3], 3)
Call: (9) length_2([2, 3], _2058)
Unify: (9) length_2([2, 3], _2058)
Call: (10) length_2([3], _2058)
Unify: (10) length_2([3], _2058)
Call: (11) length_2([], _2058)
Unify: (11) length_2([], 0)
Exit: (11) length_2([], 0)
Call: (11) _2062 is 0+1
Exit: (11) 1 is 0+1
Exit: (10) length_2([3], 1)
Call: (10) _2068 is 1+1
Exit: (10) 2 is 1+1
Exit: (9) length_2([2, 3], 2)
Call: (9) 3 is 2+1
Exit: (9) 3 is 2+1
Exit: (8) length_2([1, 2, 3], 3)
true.
[trace] ?- length_2([1,2,3],5).
Call: (8) length_2([1, 2, 3], 5)
Unify: (8) length_2([1, 2, 3], 5)
Call: (9) length_2([2, 3], _2442)
Unify: (9) length_2([2, 3], _2442)
Call: (10) length_2([3], _2442)
Unify: (10) length_2([3], _2442)
Call: (11) length_2([], _2442)
Unify: (11) length_2([], 0)
Exit: (11) length_2([], 0)
Call: (11) _2446 is 0+1
Exit: (11) 1 is 0+1
Exit: (10) length_2([3], 1)
Call: (10) _2452 is 1+1
Exit: (10) 2 is 1+1
Exit: (9) length_2([2, 3], 2)
Call: (9) 5 is 2+1
Fail: (9) 5 is 2+1
Fail: (8) length_2([1, 2, 3], 5)
false.
and to turn the trace off
[trace] ?- notrace.
true.
[debug] ?- nodebug.
true.
I won't go through each of the lines in the trace output, but if you understand syntactic unification and can follow the trace, after working through the examples given you will see how variables in Prolog are unified resulting in different modes when compared to imperative programming.
Remember that variables are only bound once in Prolog, and never reassigned, and that the numbers on the left in the trace in parenthesis, e.g. (10), are the stack level, so when a call is made to a predicate again, a new set of variables are made available, and while it may seem the are being reassigned a value, it is actually another variable in the stack, just in a different stack frame.
As an aside when learning Prolog one piece of advise I give is that it is easier to learn if you set aside what you know about imperative and functional programming, except for maybe recursion, and start from the ground up with unification and then backward chaining.
If you can read OCaml, here is a simplified version of unification and backward chaining. Note that this is not a Prolog as it does not have list or the cut operator but if you can understand it, then the ways of unification and backward chaining become apparent.
I have to add that I am not totally satisfied with my answer as I know you are a beginner and this answer is to much information to digest and requires a lot of work on your part to work through the 4 trace examples. However it does answer the question and gives a practical example with more than enough meat on the bone. I am working on trying to think of a better example which would include logical purity and that demonstrates that not only unification but relationships are key to how multiple modes can be accomplishes in one predicate. Be glad I didn't use general relativity as paraphrased by the relativist John Archibald Wheeler, spacetime tells matter how to move; matter tells spacetime how to curve.
I have been doing Prolog for a few years and I feel like my comfort with and understanding of different instantiation patterns has come in several discrete steps. The first significant hurdle is of course recursion, which is all you really need to get your head around for this problem. Basically, you know that your table assignment for two people is correct if they speak the same language, so this is your base case:
table_seating([X,Y]) :- speaksSame(X, Y).
So, what if you add a third person to the mix? You'd do something like this:
% for exposition only; do not include this clause
table_seating([A,X,Y]) :- speaksSame(A,X), speaksSame(X, Y).
Now hopefully you notice that your new work is speaksSame(A,X) but your old work has remained the same. Let's just worry about the new person and trust that we could have handled it for the remainder of the list.
table_seating([X,Y,Z|Rest]) :-
speaksSame(X, Y),
table_seating([Y,Z|Rest]).
What we're doing here is saying, assume we have at least three items in the list. Then if the first two speak the same language, and the next two plus the rest can be seated, then they can all be seated. You can always take a correctly-seated table and add a person to the front of the table, if they speak the same language as the person currently at the front of the table.
Recursion almost always has this flavor: how can I set up the minimal correct situation, the base case, and then, how can I add one more thing to that situation correctly?
Now what's interesting is that if you supply a list of some length to this predicate, it will "just work" and produce solutions of that length. Try it like so:
?- length(L, 6), table_seating(L).
You will probably get solutions (I assume speaksSame/2 will generate solutions). This is because all Prolog knows about these variables, it knows about because of your speaksSame/2 predicate. So as long as you use predicates that have many instantiation patterns in your predicates and don't force assignments to things or order things strangely, often your predicates will inherit these modes. This is a reason I recommend people use succ/2 instead of N is N0 + 1 or N0 is N - 1, because succ/2 defines a relationship between two numbers rather than performing some arithmetic (clpfd takes this idea much, much further).
In Prolog, generation and validation are one and the same thing: the table_seating predicate does both in any case, unless you deliberately produce non-relational code. i.e. the statement table_seating(X) says “X is a table seating”. if, then, X is bound and is a valid table seating, the “call” will succeed. If X is bound and invalid, the call will fail, if unbound, it will be filled with a valid seating and the call will pass.
i.e. Prolog makes sure that truth always wins. And the “making sure” is the execution/evaluation (which is implemented as a potentially failing search).
So the predicate merely needs to express what it means for something to be a table seating.

Error when defining length in SWI Prolog

I have defined a procedure named length in a file named test.pl:
% Finds the length of a list.
length([], 0).
length([_ | Tail], N) :-
length(Tail, N1),
N is 1 + N1.
When the program is run using SWI-Prolog (prolog test.pl), the following error appears:
ERROR: /home/user/test.pl:2:
No permission to modify static procedure `length/2'
Defined at /usr/lib/swi-prolog/boot/init.pl:3496
ERROR: /home/user/test.pl:3:
No permission to modify static procedure `length/2'
Defined at /usr/lib/swi-prolog/boot/init.pl:3496
I tried changing the name of the procedure from length to mylength, and the error disappears. What does this error mean? Can I define a procedure named length? If not, why can't it be done?
length/2 isn't defined in Prolog, but it's instead part of the shallow interface over native (high efficient) lists implementation. You should use the directive redefine_system_predicate.
For instance, save in a file redef_length.pl
:- redefine_system_predicate(length(?,?)).
% Finds the length of a list.
length([], 0).
length([_ | Tail], N) :-
length(Tail, N1),
N is 1 + N1.
then consult it
?- [test/prolog/redef_length].
true.
?- trace.
true.
[trace] ?- length(A,B).
Call: (8) length(_1476, _1478) ? creep
Exit: (8) length([], 0) ? creep
A = [],
B = 0 ;
Redo: (8) length(_1476, _1478) ? creep
Call: (9) length(_1718, _1738) ? creep
Exit: (9) length([], 0) ? creep
Call: (9) _1478 is 1+0 ? creep
Exit: (9) 1 is 1+0 ? creep
Exit: (8) length([_1716], 1) ? creep
A = [_1716],
B = 1
That's right. length/2 is a built-in predicate: length(?List, ?Int) is True if Int represents the number of elements in List. So the name is already used.

Prolog recursion in sum of n natural numbers

I am having trouble to understand how value of Z is constantly changing. The specific step has been indicated in the stack trace output.
Here is the code I am using for finding sum of N natural numbers -
sum1(1,1).
sum1(N, Sum) :-
Next is N-1,
sum1(Next, Z),
Sum is Z + N.
Here is the stack trace -
?- sum1(3,_).
Call: (8) sum1(3, _2668) ? creep
Call: (9) _2860 is 3+ -1 ? creep
Exit: (9) 2 is 3+ -1 ? creep
Call: (9) sum1(2, _2862) ? creep
Call: (10) _2866 is 2+ -1 ? creep
Exit: (10) 1 is 2+ -1 ? creep
Call: (10) sum1(1, _2868) ? creep
Exit: (10) sum1(1, 1) ? creep
Call: (10) _2872 is 1+2 ? creep
Exit: (10) 3 is 1+2 ? creep
Exit: (9) sum1(2, 3) ? creep **%How is Z assigned value 3 ?**
Call: (9) _2668 is 3+3 ? creep
Exit: (9) 6 is 3+3 ? EOF: exit
Thanks in advance!
It is not "changing"; each proof of sum1 gets its own versions of N, Sum, Next and Z. This is why, in the stack trace, each gets a different generated name (i.e. _2860), so Prolog can tell them apart.
As to your specific question, 2 lines above the line you ask about, that particular Sum is _2872; so proving _2872 is 1+2 requires _2872 to be 3. And this Sum is matched to the previous call sum(1, _2868), where _2868 was that sum1's Z (as you can see from 2 lines above that).

Prolog if clause returns false

I am learning Prolog and I have a small question.
I'm working on an example which "builds" a tower.
So I define 3 blocks a, b and c.
The third block c lays on top of a and b -> so it is supported by a and b.
block(a).
block(b).
block(c).
%supported(BLOCK, BY1, BY2)
supported(c,a,b).
level(BLOCK, LEVEL) :-
supported(BLOCK, X, _)
-> (level(X, LEV1), LEVEL is LEV1 + 1)
; LEVEL is 0.
I also have a function to calculate the level of a block. The problem I have is the following:
?- level(X, 0).
false.
?- level(X, 1).
X = c.
Why is it returning false for the level 0 and how can i fix it?
I would like to have a method which returns me a and b for level 0.
consider that
?- level(a,0).
true.
it's evident that when BLOCK is free the supported(BLOCK, X, _) succeeds, forcing the rule on the unintended conjuntion level(X, LEV1), LEVEL is LEV1 + 1, that indeed fails.
To correct the behaviour, bind BLOCK:
level(BLOCK, LEVEL) :-
block(BLOCK),
(supported(BLOCK, X, _) -> level(X, LEV1), LEVEL is LEV1 + 1 ; LEVEL is 0).
One can debug this using trace. (added indentation):
[trace] ?- level(X, 0).
Call: (6) level(_G2697, 0) ? creep
Call: (7) supported(_G2697, _G2771, _G2772) ? creep
Exit: (7) supported(c, a, b) ? creep
Call: (7) level(a, _G2771) ? creep
Call: (8) supported(a, _G2771, _G2772) ? creep
Fail: (8) supported(a, _G2771, _G2772) ? creep
Redo: (7) level(a, _G2771) ? creep
Call: (8) _G2770 is 0 ? creep
Exit: (8) 0 is 0 ? creep
Exit: (7) level(a, 0) ? creep
Call: (7) 0 is 0+1 ? creep
Fail: (7) 0 is 0+1 ? creep
Fail: (6) level(_G2697, 0) ? creep
false.
So what happened?
First you call level(X,0). This predicate calls supported with supported(BLOCK,X,_). There is one answer that unifies: BLOCK=a, X=b and _=c. So that means the if-then-else statement uses the then-part.
In the then-part, it queries level/2 again with level(b,LEV1), now this call results in a call to support(b,LEV1,_). For this call, it can't resolve the call, because there is no support predicate with the first value b. So now we take the else-part. We unify LEV1 is 0, thus LEV1=0 and we return.
In the return part (in the then-part), level(b,0) is the result. Now we unify LEVEL is LEV1+1, LEVEL however was already grounded as 0 and 0+1 is 1. Thus it fails on the top level.
The resolution is probably to make supported finer, and define it as: support/2.
The program reads:
block(a).
block(b).
block(c).
%supported(BLOCK, BY1, BY2)
supported(c,b).
supported(c,a).
supported(b,a).
Now the level predicate reads:
level(B,L) :-
supported(B,C),
level(C,LC),
L is LC+1.
level(_,0).

Cannot increment variable N by 1 using is/2 predicate

Cannot increment variable N by 1 using is/2 predicate. N is always 0 in the repeat loop. Why? How to increment it?
:- dynamic audible/1, flashes/1,tuned/1.
audible(false).
flashes(false).
tuned(false).
turn :-
N is 0 ,
repeat ,
(
incr(N,N1) ,
N1 =:= 5000 ,
audible(true) ,
flashes(true) -> retractall(tuned) ,
retractall(flashes) ,
retractall(audible) ,
assert( tuned(true) ) ,
assert( flashes(true) ) ,
assert( audible(true) )
) .
incr(X,X1) :- X1 is X+1 .
Because N is 0. Variables in Prolog are not assignables. Here's what happens if you trace your loop:
?- trace, turn.
Call: (7) turn ?
Call: (8) _G492 is 0 ?
Exit: (8) 0 is 0 ?
Call: (8) repeat ?
Exit: (8) repeat ?
Call: (8) incr(0, _G493) ?
Call: (9) _G495 is 0+1 ?
Exit: (9) 1 is 0+1 ?
Exit: (8) incr(0, 1) ?
Call: (8) 1=:=5000 ?
Fail: (8) 1=:=5000 ?
Redo: (8) repeat ?
Exit: (8) repeat ?
Call: (8) incr(0, _G493) ?
Call: (9) _G495 is 0+1 ?
Exit: (9) 1 is 0+1 ?
Exit: (8) incr(0, 1) ?
Call: (8) 1=:=5000 ?
Fail: (8) 1=:=5000 ?
Redo: (8) repeat ?
Exit: (8) repeat ?
Call: (8) incr(0, _G493) ?
Call: (9) _G495 is 0+1 ?
Exit: (9) 1 is 0+1 ?
Exit: (8) incr(0, 1) ?
Call: (8) 1=:=5000 ?
Fail: (8) 1=:=5000 ?
Redo: (8) repeat ?
See what's happening there? You're repeatedly asking if 1 is 5000, which fails, and then you try again. But the value of N and N1 will never change within the body of a predicate. Prolog does not have block-scoped variables like you're accustomed to. You need to make the body of the loop into a separate predicate and use recursion to accomplish what you're trying to do. It's going to look something like this:
turn :- loop(0).
loop(5000) :-
audible(true), ...
loop(N) :-
incr(N, N1),
loop(N1).
By the way, there's already a predicate succ/2 that does what you're trying to do with incr/2.
I haven't a clue what you're trying to accomplish here, but it would appear that you're trying to write procedural prolog code.
It doesn't work.
Prolog variables are write-once: having been unified with an object they cease to be variable. They become that object, until that unification is undone via backtracking.
You need to learn to think recursively and to use recursion loops to do what you want.
Your turn/0 predicate
turn :-
N is 0 ,
repeat ,
(
incr(N,N1) ,
N1 =:= 5000 ,
audible(true) ,
flashes(true) -> retractall(tuned) ,
retractall(flashes) ,
retractall(audible) ,
assert( tuned(true) ) ,
assert( flashes(true) ) ,
assert( audible(true) )
) .
does the following. It:
unifies N with 0,
increments N1 with N+1, making N1 = 1
fails if N1 is something other than 5000 (which it is).
On failure, the prolog engine starts backtracking...
backtracking through incr/2 undoes N1's binding, making it variable again.
backtracking into repeat/0, succeeds again.
At this point, you're back to where you started, with N bound to 0.
Wash, rinse, repeat.

Resources