Reputation: 43
I am new to Prolog. I am trying to write a predicate which returns the number of nodes of a binary tree at a given depth in the tree. For example, the following tree
has 1 node of depth 0 (the root node), 2 nodes of depth 1, 3 nodes of depth 2 and 3 nodes of depth 3.
In my program, binary trees are represented as lists of the form [value, left-child, right-child]
, where left and right children can themselves be represented the same way. For example, here is the representation of the above tree:
[8, [3, [1, [], []],
[6, [4, [], []],
[7, [], []]]],
[10, [],
[14,
[13, [], []],
[]]]]
Here is what I've come up with so far:
nbNodes([_,_,_],1,0).
nbNodes([_,LC,RC],N2,D2) :-
nbNodes(LC,NL,D), nbNodes(RC,NR,D), N2 is NL+NR, D2 is D+1.
Based on my limited understanding of Prolog, this means that:
However, when I test my code, the numbers returned (if any) are wrong. For example, the following code outputs "false" instead of "3":
nbNodes([8, [3, [1, [], []], [6, [4, [], []], [7, [], []]]], [10, [], [14, [13, [], []], []]]], N, 2).
What am I doing wrong ? Many thanks in advance.
Upvotes: 3
Views: 491
Reputation: 683
How about
nbNodes( [],0,_).
nbNodes( [_,_,_],1,0).
nbNodes( [_,LC,RC],N2,D2):-
D2 > 0,
D is D2-1,
nbNodes( LC,NL,D),
nbNodes( RC,NR,D),
N2 is NL+NR.
That is the result:
?- T = [8,[3,[1,[],[]],[6,[4,[],[]],[7,[],[]]]],[10,[],[14,[13,[],[]],[]]]],
nbNodes(T,N,0).
T = [8, [3, [1, [], []], [6, [4, []|...], [7|...]]], [10, [], [14, [13|...], []]]],
N = 1 ;
false.
?- T = [8,[3,[1,[],[]],[6,[4,[],[]],[7,[],[]]]],[10,[],[14,[13,[],[]],[]]]],
nbNodes(T,N,1).
T = [8, [3, [1, [], []], [6, [4, []|...], [7|...]]], [10, [], [14, [13|...], []]]],
N = 2 ;
false.
?- T = [8,[3,[1,[],[]],[6,[4,[],[]],[7,[],[]]]],[10,[],[14,[13,[],[]],[]]]],
nbNodes(T,N,2).
T = [8, [3, [1, [], []], [6, [4, []|...], [7|...]]], [10, [], [14, [13|...], []]]],
N = 3 ;
false.
?- T = [8,[3,[1,[],[]],[6,[4,[],[]],[7,[],[]]]],[10,[],[14,[13,[],[]],[]]]],
nbNodes(T,N,3).
T = [8, [3, [1, [], []], [6, [4, []|...], [7|...]]], [10, [], [14, [13|...], []]]],
N = 3 ;
false.
?- T = [8,[3,[1,[],[]],[6,[4,[],[]],[7,[],[]]]],[10,[],[14,[13,[],[]],[]]]],
nbNodes(T,N,4).
T = [8, [3, [1, [], []], [6, [4, []|...], [7|...]]], [10, [], [14, [13|...], []]]],
N = 0.
The two major changes are that
D
from D2
, before I call the predicate again and do not calculate D2
from D
after the recursive calls.I guess you are asking what the difference is, because you have been told that Prolog is declarative and thus we need to only specify what is the case (our knowledge base) and not how something can be inferred from our knowledge.
Well, you have been lied at. Prolog is not purely declarative, since there is an order, in which it searches for an answer.
If you want to prove a goal G
by the use of a clause
G :- L1,L2,L3.
Prolog tries to prove L1, then L2, then L3 - although from a logical view, this clause says nothing but
IF L1 and L2 and L3 THEN G,
which is logically equivalent to
IF L3 and L1 and L2 THEN G
There might be a proof, if Prolog checked all possible orders, yet it doesn't.
In addition, for many predicates, certain arguments need to be instantiated in order for the predicates to work. One of such predicates is is/2
. Its right hand side needs to be fully instantiated for is/2
to work.
Your predicate needs its third argument to be instantiated. When you call
nbNodes(LC,NL,D)
and nbNodes(RC,NR,D)
, D
is not instantiated.
Even if you changed the order of your clauses and put D2 is D+1
before those clauses, this doesn't work, since is/2
needs its right hand side to be fully instantiated, and D
is not yet instantiated at that point.
Try asking ?- X is 2
. and ?- 2 is X.
to see the difference.
For a fuller picture, you need to dig into Prolog's (partial) implementation of the resolution principle. If you want to have a more declarative kind of Prolog, have a look at Constraint Logic Programming.
Upvotes: 4