Please explain this example of Prolog recursion - recursion
I'm learning Prolog and I'm having a hard time with recursion. The simple cases with a database I can understand, but I can't follow this exercise, where redu/2 is implemented, which will remove the duplicates of a given list and give the new list as second argument:
redu([],[]).
redu([H|T], Result):-
member(H,T),
redu(T,Result).
redu([H|T], [H|Result]):-
redu(T, Result).
A trace gives me this:
[trace] ?- redu([a,b,b,c,a], X).
Call: (8) redu([a, b, b, c, a], _35630) ? creep
Call: (9) lists:member(a, [b, b, c, a]) ? creep
Exit: (9) lists:member(a, [b, b, c, a]) ? creep
Call: (9) redu([b, b, c, a], _35630) ? creep
Call: (10) lists:member(b, [b, c, a]) ? creep
Exit: (10) lists:member(b, [b, c, a]) ? creep
Call: (10) redu([b, c, a], _35630) ? creep
Call: (11) lists:member(b, [c, a]) ? creep
Fail: (11) lists:member(b, [c, a]) ? creep
Redo: (10) redu([b, c, a], _35630) ? creep
Call: (11) redu([c, a], _35900) ? creep
Call: (12) lists:member(c, [a]) ? creep
Fail: (12) lists:member(c, [a]) ? creep
Redo: (11) redu([c, a], _35900) ? creep
Call: (12) redu([a], _35906) ? creep
Call: (13) lists:member(a, []) ? creep
Fail: (13) lists:member(a, []) ? creep
Redo: (12) redu([a], _35906) ? creep
Call: (13) redu([], _35912) ? creep
Exit: (13) redu([], []) ? creep
Exit: (12) redu([a], [a]) ? creep
Exit: (11) redu([c, a], [c, a]) ? creep
Exit: (10) redu([b, c, a], [b, c, a]) ? creep
Exit: (9) redu([b, b, c, a], [b, c, a]) ? creep
Exit: (8) redu([a, b, b, c, a], [b, c, a]) ? creep
X = [b, c, a]
I would really appreciate it if somebody could explain to me in natural language what recursion does and how to read the clauses. Like with the second clause, is it right that it reads as "remove duplicates from list H|T and output Result if the head of that list is a member of the tail and remove the duplicates from the tail and output the result? But how can the two Results be the same? And I also don't get which rule is activated when. When does it go forward in my list of clauses? When does it go back?
Sorry for all the questions. I really want to understand everything.
So you have
redu([], []).
redu([H|T], R ):- member(H, T), redu(T, R).
redu([H|T], [H|R]):- redu(T, R).
==
redu([], []).
redu([H|T], X ):- member(H, T), X = R , redu(T, R).
redu([H|T], X):- X = [H|R], redu(T, R).
==
redu([], []).
redu([H|T], X ):- ( member(H, T), X = R
; X = [H|R]), redu(T, R).
==
redu([], []).
redu([H|T], X ):- disj(H, T, X, R), redu(T, R).
disj(H, T, R, R):- member(H, T).
disj(H,_T, [H|R], R).
These two new redu/2 clauses are mutually exclusive, so the code can be easier to understand in this form. Whether disj/4 includes H into the list X being built (in the top-down manner) or not - and however many times it succeeds (*) - after disj/4 does its thing, the recursive call to redu/2 is simply made.
So we read redu(L,X) as "for the head element H in L=[H|T], if there are some more Hs in T, either don't include H in the 'output' list X, or do; and for a unique H - such that does not occur in T - include it in X always; and then, having dealt with this head element H of L, proceed to deal with the rest of the elements in the list in the same manner." In other words, do this for each element in the list L.
This recursive definition follows naturally the inductive definitions of lists as [H|T] or [] structures.
(*) (do take note that A. member may succeed more than once, and B. the two clauses of disj/4 are not mutually exclusive).
With your example,
redu([a,b,b,c,a], X)
==
disj( a, [b,b,c,a], X,R), % AND redu([b,b,c,a], R) i.e.
disj( b, [b,c,a], R,R2), % AND redu([b,c,a], R2) i.e.
disj( b, [c,a], R2,R3), % AND redu([c,a], R3) i.e.
disj( c, [a], R3,R4), % AND redu([a], R4) i.e.
disj( a, [], R4,R5), % AND the final clause,
redu( [], R5).
Now you can try each disj/4 invocation and see what is happening there, like
33 ?- disj(a,[b,b,c,a], X,R).
X = R ;
X = [a|R].
34 ?- disj(b,[c,a], R2,R3).
R2 = [b|R3].
Thus the whole example becomes
(X = R ; X = [a|R]), % [ a
(R = R2 ; R = [b|R2]), % b
R2 = [b|R3], % b
R3 = [c|R4], % c
R4 = [a|R5], % a
R5 = []. % ]
or
ex(X):-
(X = R ; X = [a|R]),
(R = R2 ; R = [b|R2]),
R2 = [b,c,a].
which is
42 ?- ex(X).
X = [b, c, a] ;
X = [b, b, c, a] ;
X = [a, b, c, a] ;
X = [a, b, b, c, a].
Any recursive implementation has at least two clauses - base clauses, and oone or more recursive clauses.
Base clauses deal with degenerate cases: empty lists, zeros, and so on. They give simple answers - for example, in your case the base clause states that the answer for an empty list is an empty list.
The recursive clauses deal separately with a situation when the item is on the list (second clause), and when the item is not on the list (third clause). The second clause says that when an item is found on the tail portion of the list (member of T) then it should not be added to the result now; it will be added later. If, on the other hand, this is the last item, third clause adds it to the output list.
But then, eventually, the member check will fail (b is not a member of [c,a]), but how does it work then?
Once member check fails, Prolog goes to the third clause, which adds H to the output list with [H|Result], and proceeds to computing the rest of the Result from the tail part T of the list with redu(T, Result).
Note 1: There is one mistake in the program, though: the last clause needs to be conditioned on the item not being on the tail portion of the list:
redu([H|T], [H|Result]):-
\+ member(H,T),
redu(T, Result).
This should prevent Prolog from going into the clause if the second clause has executed.
Note 2: The other option is to use cut in the second clause, but this option is highly discouraged.
Related
A predicate that takes a list and repeats each element X amount of times - Prolog
I can get the result to be true, but when I attempt to make it false I feel like it is in an endless loop. repeat(L,N,Result):- rHelp(L,N,[],Result). rHelp(_,_,Result,Result). rHelp([H|T],N,L1,L2):- dupe(H,N,[],L3), append(L1,L3,L4), rHelp(T,N,L4,L2). dupe(_,0,L,L). dupe(H,N,L,Result):- N1 is N-1, append(L,[H],L1), dupe(H,N1,L1,Result). Example Test: repeat( [a, b, c], 2, [a, a, b, b, c, c] ) repeat( [1, a, 2, b], 0, [ ] ) repeat( [1, 1, 2], 3, [1, 1, 1, 1, 1, 1, 2, 2, 2] ) which are all True. I am just trying to get a false result.
One reason it's hard to make your program fail is that it describes too many incorrect solutions: ?- repeat([a, b, c], 2, Result). Result = [] ; Result = [a, a] ; Result = [a, a, b, b] ; Result = [a, a, b, b, c, c] ; % nontermination The reason you accept too many solutions is the first clause of rHelp/4: rHelp(_,_,Result,Result). Here you say that for any input list, at any point in the computation where you have an intermediate result Result, that is a correct solution. But this is not the case. The intermediate result is only a complete result once you have exhausted the entire input list. This clause should be: rHelp([], N, Result, Result). Note that I found this essentially by pattern matching. Adjacent clause heads like foo(_, Bar). foo([H|T], Bar) :- ... simply look incorrect. Why is the _ not an empty list? In most cases a predicate like this would have mutually exclusive patterns in the head, and here that is not the case. With this fixed, we can try the test again: ?- repeat([a, b, c], 2, Result). Result = [a, a, b, b, c, c] ; % nontermination Better! But it still goes searching for more solutions although there are none. This, too, is a case of clauses not being mutually exclusive: dupe(_,0,L,L). dupe(H,N,L,Result):- N1 is N-1, ... If the second argument is not 0, the second clause applies. If the second argument is 0, the first clause applies... but so does the second! After finding a solution using the first clause, Prolog will backtrack and execute the second clause with N = 0. Then N1 will become -1, and your program goes off recursively looking for negative infinity. The fix is to add a guard N > 0 in the second clause. And with these two changes, the test works as desired: ?- repeat([a, b, c], 2, Result). Result = [a, a, b, b, c, c] ; false. One general point to observe here is that it was easier to understand the behavior of your predicate by using less specific queries. There is no need to specify a fixed list for the Result argument: Leave it free and see what Prolog gives you!
Prolog recursive function not behaving as expected
I'm trying to implement the recursive version of the Fibonacci sequence in Prolog. Below is the code: fib(0,F) :- F is 0. fib(1,F) :- F is 1. fib(N,F) :- N > 1, AA is (N - 1), BB is (N - 2), fib(AA,CC), fib(BB,DD), RR is (CC + DD), F == RR, F is RR. The problem is that it's not behaving as I logically expect it to. When I use trace to call fib(3,2), I get the following lines: Call: (7) fib(3, 2) ? creep Call: (8) 3>1 ? creep Exit: (8) 3>1 ? creep Call: (8) _G2569 is 3+ -1 ? creep Exit: (8) 2 is 3+ -1 ? creep Call: (8) _G2572 is 3+ -2 ? creep Exit: (8) 1 is 3+ -2 ? creep Call: (8) fib(2, _G2573) ? creep Call: (9) 2>1 ? creep Exit: (9) 2>1 ? creep Call: (9) _G2575 is 2+ -1 ? creep Exit: (9) 1 is 2+ -1 ? creep Call: (9) _G2578 is 2+ -2 ? creep Exit: (9) 0 is 2+ -2 ? creep Call: (9) fib(1, _G2579) ? creep Call: (10) _G2578 is 1 ? creep Exit: (10) 1 is 1 ? creep What catches my attention is the last call, Call: (10), which says "_G2578 is 1 ?", even though I'm calling fib(1, _G2579). My expectation is that it's _G2579 that's going to be changed, but that does not appear to be the case. I need to find out why because I highly suspect that this is why fib(3,2) is returning false instead of true.
The problem, if I'm not wrong, is in F == R that check if F (a newly introduced term without a value) is equal to R. If you change it in F = R so unifing F with R (an in redundant following F is R), your fib/2 should work. But I propose you some semplification. (1) the terminale case fib(0,F) :- F is 0. is good but you can write it as fib(0,0). (2) same semplification for the other terminal case: you can write it as fib(1,1). (3) in the general clause, you don't need two different variables F and RR with the same (unified) value; you can use only F in the following way fib(N,F) :- N > 1, AA is (N - 1), BB is (N - 2), fib(AA,CC), fib(BB,DD), F is (CC + DD).
Decompression of a list in prolog
I need to decompress a list in prolog , like in the example below : decode([[a,1],[b,2],[c,1],[d,3]],L). L = [a, b, b, c, d, d, d] ; I made this code : divide(L,X,Y):-length(X,1),append(X,Y,L). divide2(L,X,Y):-divide(L,[X|_],[Y|_]). makelist(_,N,[]):- N =< 0 . makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result). makelist2(L,L2):-divide2(L,X,Y),makelist(X,Y,L2). decode([],[]). decode([H|T],L):-makelist2(H,H2),append(H2,L,L2),decode(T,L2). and when i call makelist2([a,3],L2). L2 = [a,a,a]. but when i call decode([[a,3],[b,1],[c,4]],L) runs continuously. What am i doing wrong ?
Another variation of the theme, using a slightly modified version of Boris' repeat/3 predicate: % True when L is a list with N repeats of X repeat([X, N], L) :- length(L, N), maplist(=(X), L). decode(Encoded, Decoded) :- maplist(repeat, Encoded, Expanded), flatten(Expanded, Decoded). If Encode = [[a,1],[b,2],[c,1],[d,3]], then in the above decode/2, the maplist/3 call will yield Expanded = [[a],[b,b],[c],[d,d,d]], and then the flatten/2 call results in Decoded = [a,b,b,c,d,d,d]. In SWI Prolog, instead of flatten/2, you can use append/2 since you only need a "flattening" at one level. EDIT: Adding a "bidirectional" version, using a little CLPFD: rle([], []). rle([X], [[1,X]]). rle([X,Y|T], [[1,X]|R]) :- X \== Y, % use dif(X, Y) here, if available rle([Y|T], R). rle([X,X|T], [[N,X]|R]) :- N #= N1 + 1, rle([X|T], [[N1,X]|R]). This will yield: | ?- rle([a,a,a,b,b], L). L = [[3,a],[2,b]] ? ; (1 ms) no | ?- rle(L, [[3,a],[2,b]]). L = [a,a,a,b,b] ? ; no | ?- rle([a,a,a,Y,Y,Z], [X, [N,b],[M,c]]). M = 1 N = 2 X = [3,a] Y = b Z = c ? a no | ?- rle([A,B,C], D). D = [[1,A],[1,B],[1,C]] ? ; C = B D = [[1,A],[2,B]] ? ; B = A D = [[2,A],[1,C]] ? ; B = A C = A D = [[3,A]] ? ; (2 ms) no | ?- rle(A, [B,C]). A = [D,E] B = [1,D] C = [1,E] ? ; A = [D,E,E] B = [1,D] C = [2,E] ? ; A = [D,E,E,E] B = [1,D] C = [3,E] ? ; ... | ?- rle(A, B). A = [] B = [] ? ; A = [C] B = [[1,C]] ? ; A = [C,D] B = [[1,C],[1,D]] ? ; ... As #mat suggests in his comment, in Prolog implementations that have dif/2, then dif(X,Y) is preferable to X \== Y above.
The problem is in the order of your append and decode in the last clause of decode. Try tracing it, or even better, trace it "by hand" to see what happens. Another approach: see this answer. So, with repeat/3 defined as: % True when L is a list with N repeats of X repeat(X, N, L) :- length(L, N), maplist(=(X), L). You can write your decode/2 as: decode([], []). decode([[X,N]|XNs], Decoded) :- decode(XNs, Decoded_rest), repeat(X, N, L), append(L, Decoded_rest, Decoded). But this is a slightly roundabout way to do it. You could define a difference-list version of repeat/3, called say repeat/4: repeat(X, N, Reps, Reps_back) :- ( succ(N0, N) -> Reps = [X|Reps0], repeat(X, N0, Reps0, Reps_back) ; Reps = Reps_back ). And then you can use a difference-list version of decode/2, decode_1/3 decode(Encoded, Decoded) :- decode_1(Encoded, Decoded, []). decode_1([], Decoded, Decoded). decode_1([[X,N]|XNs], Decoded, Decoded_back) :- repeat(X, N, Decoded, Decoded_rest), decode_1(XNs, Decoded_rest, Decoded_back). ?- decode([[a,1],[b,2],[c,1],[d,3]],L). L = [a, b, b, c, d, d, d]. ?- decode([[a,3],[b,1],[c,0],[d,3]],L). L = [a, a, a, b, d, d, d]. ?- decode([[a,3]],L). L = [a, a, a]. ?- decode([],L). L = [].
You can deal with both direction with this code : :- use_module(library(lambda)). % code from Pascal Bourguignon packRuns([],[]). packRuns([X],[[X]]). packRuns([X|Rest],[XRun|Packed]):- run(X,Rest,XRun,RRest), packRuns(RRest,Packed). run(Var,[],[Var],[]). run(Var,[Var|LRest],[Var|VRest],RRest):- run(Var,LRest,VRest,RRest). run(Var,[Other|RRest],[Var],[Other|RRest]):- dif(Var,Other). %end code pack_1(In, Out) :- maplist(\X^Y^(X = [V|_], Y = [V, N], length(X, N), maplist(=(V), X)), In, Out). decode(In, Out) :- when((ground(In); ground(Out1)),pack_1(Out1, In)), packRuns(Out, Out1). Output : ?- decode([[a,1],[b,2],[c,1],[d,3]],L). L = [a, b, b, c, d, d, d] . ?- decode(L, [a,b,b,c,d,d,d]). L = [[a, 1], [b, 2], [c, 1], [d, 3]] .
a compact way: decode(L,D) :- foldl(expand,L,[],D). expand([S,N],L,E) :- findall(S,between(1,N,_),T), append(L,T,E). findall/3 it's the 'old fashioned' Prolog list comprehension facility
decode is a poor name for your predicate: properly done, you predicate should be bi-directional — if you say decode( [[a,1],[b,2],[c,3]] , L ) You should get L = [a,b,b,c,c,c]. And if you say decode( L , [a,b,b,c,c,c] ) . You should get L = [[a,1],[b,2],[c,3]]. So I'd use a different name, something like run_length_encoding/2. I might also not use a list to represent individual run lengths as [a,1] is this prolog term: .(a,.(1,[]). Just use a simple term with arity 2 — myself, I like using :/2 since it's defined as an infix operator, so you can simply say a:1. Try this on for size: run_length_encoding( [] , [] ) . % the run-length encoding of the empty list is the empty list. run_length_encoding( [X|Xs] , [R|Rs] ) :- % the run-length encoding of a non-empty list is computed by rle( Xs , X:1 , T , R ) , % - run-length encoding the prefix of the list run_length_encoding( T , Rs ) % - and recursively run-length encoding the remainder . % Easy! rle( [] , C:N , [] , C:N ) . % - the run is complete when the list is exhausted. rle( [X|Xs] , C:N , [X|Xs] , C:N ) :- % - the run is complete, X \= C % - when we encounter a break . % rle( [X|Xs] , X:N , T , R ) :- % - the run continues if we haven't seen a break, so.... N1 is N+1 , % - increment the run length, rle( Xs, X:N1, T, R ) % - and recurse down. . % Easy!
In direct answer to the original question of, What am I doing wrong?... When I ran the original code, any expected use case "ran indefinitely" without yielding a result. Reading through the main predicate: decode([],[]). This says that [] is the result of decoding []. Sounds right. decode([H|T],L) :- makelist2(H,H2), append(H2,L,L2), decode(T,L2). This says that L is the result of decoding [H|T] if H2 is an expansion of H (which is what makelist2 does... perhaps - we'll go over that below), and H2 appended to this result gives another list L2 which is the decoded form of the original tail T. That doesn't sound correct. If I decode [H|T], I should (1) expand H, (2) decode T giving L2, then (3) append H to L2 giving L. So the corrected second clause is: decode([H|T], L) :- makelist2(H, H2), decode(T, L2), append(H2, L2, L). Note the argument order of append/3 and that the call occurs after the decode of the tail. As Boris pointed out previously, the incorrect order of append and the recursive decode can cause the continuous running without any output as append with more uninstantiated arguments generates a large number of unneeded possibilities before decode can succeed. But now the result is: | ?- decode([[a,3]], L). L = [a,a,a] ? ; L = [a,a,a,a] ? ; ... If you try out our other predicates by hand in the Prolog interpreter, you'll find that makelist2/2 has an issue: It produces the correct result, but also a bunch of incorrect results. Let's have a look at makelist2/2. We can try this predicate by itself and see what happens: | ?- makelist2([a,3], L). L = [a,a,a] ? ; L = [a,a,a,a] ? ; ... There's an issue: makelist2/2 should only give the first solution, but it keeps going, giving incorrect solutions. Let's look closer at makelist/2: makelist2(L,L2) :- divide2(L,X,Y), makelist(X,Y,L2). It takes a list L of the form [A,N], divides it (via divide2/3) into X = A and Y = N, then calls an auxiliary, makelist(X, Y, L2). makelist(_,N,[]):- N =< 0 . makelist(X,Y,[X|Result]):-Y1 is Y-1,makelist(X,Y1,Result). makelist/3 is supposed to generate a list (the third argument) by replicating the first argument the number of times given in the second argument. The second, recursive clause appears to be OK, but has one important flaw: it will succeed even if the value of Y is less than or equal to 0. Therefore, even though a correct solution is found, it keeps succeeding on incorrect solutions because the base case allows the count to be =< 0: | ?- makelist(a,2,L). L = [a,a] ? ; L = [a,a,a] ? ; We can fix makelist/2 as follows: makelist(_,N,[]):- N =< 0 . makelist(X,Y,[X|Result]):- Y > 0, Y1 is Y-1, makelist(X,Y1,Result). Now the code will generate a correct result. We just needed to fix the second clause of decode/2, and the second clause of makelist/3. | ?- decode([[a,3],[b,4]], L). L = [a,a,a,b,b,b,b] yes The complete, original code with just these couple of corrections looks like this: divide(L, X, Y) :- length(X, 1), append(X, Y, L). divide2(L, X, Y) :- divide(L, [X|_], [Y|_]). makelist(_, N, []) :- N =< 0 . makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result). makelist2(L, L2) :- divide2(L, X, Y), makelist(X, Y, L2). decode([], []). decode([H|T], L) :- makelist2(H,H2), decode(T,L2), append(H2,L2,L). Note some simple, direct improvements. The predicate, divide2(L, X, Y) takes a list L of two elements and yields each, individual element, X and Y. This predicate is unnecessary because, in Prolog, you can obtain these elements by simple unification: L = [X, Y]. You can try this right in the Prolog interpreter: | ?- L = [a,3], L = [X,Y]. L = [a,3] X = a Y = 3 yes We can then completely remove the divide/3 and divide2/3 predicates, and replace a call to divide2(L, X, Y) with L = [X,Y] and reduce makelist2/2 to: makelist2(L, L2) :- L = [X, Y], makelist(X, Y, L2). Or more simply (because we can do the unification right in the head of the clause): makelist2([X,Y], L2) :- makelist(X, Y, L2). You could just remove makelist2/2 and call makelist/2 directly from decode/2 by unifying H directly with its two elements, [X, N]. So the original code simplifies to: makelist(_, N, []) :- N =< 0 . makelist(X, Y, [X|Result]) :- Y > 0, Y1 is Y-1, makelist(X,Y1,Result). decode([], []). decode([[X,N]|T], L) :- makelist(X, N, H2), decode(T, L2), append(H2, L2, L). And makelist/3 can be performed a bit more clearly using one of the methods provided in the other answers (e.g., see Boris' repeat/3 predicate).
Prolog Recursion returns multiple results
To start off this is a homework question poised to me. I am supposed to write a predicate btree_height\2 that takes a Binary tree and (for now) just returns the height of the tree. A binary tree is represented as: node(node(leaf, x, leaf), x, node(leaf, x, leaf)) where the x's are integer values of the node. (This is just an example tree). My code is as follows: btree_height(leaf, 0). btree_height(node(leaf,_,leaf), 1). btree_height(node(LT,_,RT), D):- btree_height(LT, DL), btree_height(RT, DR), D is max(DL,DR)+1. The problem that I am having is that when I call btree_height(BT, D) and supply it with a BT if the depth is 4 then it recurses 4 times and "returns" the number 4 four times. According to my professor this is an incorrect behavior as it should only return the number 4 once. (Using the example above it returns the number 2 twice) This is my first time coding in Prolog and I have no idea where I should start looking. This is technically SWI-Prolog if it makes a difference...
Since this is homework, I won't give you the full solution. When your predicate hits a node that matches node(leaf, _, leaf), it first executes the second clause. That returns one. Then, when you ask it to backtrack, it will also execute the third clause, because that also matches the input with LT=leaf and RT=leaf, so it will recurse twice and hit the leaf case both times. Next time, if you have to debug this kind of problem yourself, trace/1 is a good tool: 2 ?- trace. true. [trace] 2 ?- btree_height(node(node(leaf, x, leaf), x, node(leaf, x, leaf)), H). Call: (6) btree_height(node(node(leaf, x, leaf), x, node(leaf, x, leaf)), _G821) ? creep Call: (7) btree_height(node(leaf, x, leaf), _G903) ? creep Exit: (7) btree_height(node(leaf, x, leaf), 1) ? creep Call: (7) btree_height(node(leaf, x, leaf), _G903) ? creep Exit: (7) btree_height(node(leaf, x, leaf), 1) ? creep Call: (7) _G821 is max(1, 1)+1 ? creep Exit: (7) 2 is max(1, 1)+1 ? creep Exit: (6) btree_height(node(node(leaf, x, leaf), x, node(leaf, x, leaf)), 2) ? creep H = 2 ; Redo: (7) btree_height(node(leaf, x, leaf), _G903) ? creep Call: (8) btree_height(leaf, _G903) ? creep Exit: (8) btree_height(leaf, 0) ? creep Call: (8) btree_height(leaf, _G903) ? creep Exit: (8) btree_height(leaf, 0) ? creep Call: (8) _G911 is max(0, 0)+1 ? creep Exit: (8) 1 is max(0, 0)+1 ? creep Exit: (7) btree_height(node(leaf, x, leaf), 1) ? creep Call: (7) _G821 is max(1, 1)+1 ? creep Exit: (7) 2 is max(1, 1)+1 ? creep Exit: (6) btree_height(node(node(leaf, x, leaf), x, node(leaf, x, leaf)), 2) ? creep H = 2 (Where it says creep, I pressed Enter.)
Recursion in prolog
I dont think I understand how recursion works in prolog The following code (a power function) pow(_,0,1). pow(X,Y,Z) :- Y1 is Y - 1 , pow(X,Y1,Z1) , Z is Z1*X . Creates the following trace: [trace] ?- pow(2,2,X). Call: (6) pow(2, 2, _G368) ? creep Call: (7) _G444 is 2+ -1 ? creep Exit: (7) 1 is 2+ -1 ? creep Call: (7) pow(2, 1, _G443) ? creep Call: (8) _G447 is 1+ -1 ? creep Exit: (8) 0 is 1+ -1 ? creep Call: (8) pow(2, 0, _G446) ? creep Exit: (8) pow(2, 0, 1) ? creep Call: (8) _G450 is 1*2 ? creep Exit: (8) 2 is 1*2 ? creep Exit: (7) pow(2, 1, 2) ? creep Call: (7) _G368 is 2*2 ? creep Exit: (7) 4 is 2*2 ? creep Exit: (6) pow(2, 2, 4) ? creep I dont understand how the last state : 'Z is Z1*X' works. When is this function called? When the base case is reached? How does the base case ever get called? Thanks
The main point is that pow is not a function. It's a predicate. Prolog doesn't really evaluate pow, it tries satisfy its conditions. And when is the first clause reached? It's tried every time. But unless the second argument is 0 and the third one is 1 (or they are variables that can be unified with those values), it fails. And when the first clause fails, the second one is tried.
You can think of pow as a function that is split in two clauses that deal with different parameter values. The function is recursive, which is triggered by the recursive call in the second clause. But after this call, there is still something to do, the Z is Z1*1 goal. These "dangling" computations are done when the recursion has terminated and control "bubbles" upward again, on the way back so to speak. (There is a name for this kind of recursion which I can't remember). Look at this commented trace: [trace] ?- pow(2,2,X). % initial call Call: (6) pow(2, 2, _G368) ? creep % the second clause is picked for this call, % the third argument is an uninstantiated variable, represented by _G368 Call: (7) _G444 is 2+ -1 ? creep % the first goal in this claus is "Y1 is Y -1", which is here % translated with its bindings Exit: (7) 1 is 2+ -1 ? creep % the is/2 goal has been called, and has provided a binding for "Y1" Call: (7) pow(2, 1, _G443) ? creep % this is the first recursive call, with the new arguments 2, 1 and an % undefined Z1 Call: (8) _G447 is 1+ -1 ? creep % again the second clause is used, this is the first goal in it, % calling is/2 Exit: (8) 0 is 1+ -1 ? creep % is/2 delivers a binding for the current Y1, 0 Call: (8) pow(2, 0, _G446) ? creep % the next (second) recursive call; see how at this point non of the % "Z is Z1*X" "statements" have been reached Exit: (8) pow(2, 0, 1) ? creep % the second recursive call matches the first clause; this is where % the base case is used! it can immediately "Exit" as with the match % to the clause all bindings have been established already; the third % argument is instantiated to 1 Call: (8) _G450 is 1*2 ? creep % now the recursion has terminated, and control is passed back to that % more recent calling clause (this was the one where Y1 has been bound % to 0); now the "Z is Z1*X" can be tried for the first time, and Z % can be instantiated ("unified") Exit: (8) 2 is 1*2 ? creep % this is the result of this unification, Z is bound to 2; % with this, this level in the stack of recursive calls has been completed... Exit: (7) pow(2, 1, 2) ? creep % ... and this is the result ("Exit") of this call, showing all % instantiated parameters Call: (7) _G368 is 2*2 ? creep % but this just brings us back one more level in the call stack, to a % pending execution (this was the one where Y1 has been bound to 1), % now the pending execution can be performed Exit: (7) 4 is 2*2 ? creep % here you see the result of the execution of is/2, binding Z to 4 Exit: (6) pow(2, 2, 4) ? creep % and this finishes the initial call of the predicate, delivering a % binding for the X in the query, 4; you can tell that the recursive % call stack as been processed completely by looking at the "stack % depth indicator", (6), which matches the initial (6) when the trace % started (they don't necessarily start with 0 or 1).
Every line in the trace with the asterisk (*) is using the "Z is Z1 * X" rule. This code works by providing the following recursive definition of the power function: X^0 = 1 for all X. X^Y = X^(Y-1) * X The Z, Z1 and Y1 variables are artifacts of the fact that Prolog needs a way to refer to intermediate results; you call Y-1 Y1 and you call X^(Y-1) Z1. This gets to the base case by decreasing the exponent (Y) by one (yielding Y1) at each level of the recursion until Y = 0 and the first case of the definition applies.