2

I have some code

tree1(tree(1,
            tree(2,
                tree(3,nil,nil),
                tree(4,nil,nil)),
            tree(5,
                tree(6,nil,nil),
                tree(7,nil,nil))
        )
    ).
rbt_count_nodes(e,0):-!.
rbt_count_nodes(t(_,L,R),N):-
    rbt_count_nodes(L,NL),
    rbt_count_nodes(R,NR),
    N=NL+NR+1.

?-tree1(T),rbt_count_nodes(T,N),write(N).

But goal always return No. Why ?

2 Answers 2

5
rbt_count_nodes(t(_,L,R),N)

should become

rbt_count_nodes(tree(_,L,R),N)

and

N=NL+NR+1

should become

N is NL + NR + 1

((=)/2 is used to perform unification, (is)/2 to perform arithmetic).

and

rbt_count_nodes(e,0):-!.

should become

rbt_count_nodes(nil,0).

After those three edits it should be fine, though I cannot test so I might be proven wrong.

Sign up to request clarification or add additional context in comments.

1 Comment

to this I could only add that Prolog data is symbolic and Prolog unification is structural unification of symbolic data; while is forces an argument expression under assumption that it describes an arithmetic entity. And you can always test at ideone.com . :)
4

Beside the notes given in another answer (using is/2 instead of =/2 and the typos in the name of the terms t->tree and e->empty), you should consider using an accumulator to allow the prolog system to do tail recursion:

rbt_count_nodes(T,N):-
  rbt_count_nodes(T, 0, N).

rbt_count_nodes(nil,N, N):-!.
rbt_count_nodes(tree(_,L,R),C,N):-
    succ(C, C1),
    rbt_count_nodes(L,C1,NL),
    rbt_count_nodes(R,NL,N).

Procedure rbt_count_nodes/2 just calls rbt_count_nodes/3 with zero as the second argument (accumulator). Upon each recursion step, this accumulator gets incremented by one and does recursion. The base case just unifies the accumulator with your output allowing the system to do tail recursion and economize on stack space.

[edit]

As per comments, to make it truly tail recursive (that is, all recursive calls are tail calls) you can add a new clause to rbt_count_nodes/3 (and modify another):

rbt_count_nodes(nil,N, N):-!.
rbt_count_nodes(tree(Node,tree(LNode, LL, LR),R),C,N):-
  rbt_count_nodes(tree(Node, LL, tree(LNode, LR, R)), C, N).
rbt_count_nodes(tree(_,nil,R),C,N):-
  succ(C, C1),
  rbt_count_nodes(R,C1, N).

With this approach, the first clause deal with an empty node, the second one deals with the left side of the tree which just "moves" the branch to the right hand side of the current node, and the third clause just computes the count of nodes.

8 Comments

this code is not tail recursive. And you don't need the cut, as nil and tree(_,_,_) are mutually-exclusive choices.
@Will Ness: This code is tail recursive, why do you say otherwise ?. I just modified OP code, so I left the cut.
@Mog: You're right about the variable name. Changed that name!
It's not tail recursive because the predicate calls itself before the last instruction (even if the last instruction is a call to istelf too). That means that Prolog will have to save the context, unlike in a tail recursive approach.
I'd say it is technically tail recursive because upon last recursive call it will discard context. However you are right that the first recursive call to itself does need the retain context.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.