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
- I added a clause for empty binary trees.
- I calculated
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.