我是 Prolog 的新手。我正在尝试编写一个谓词,它返回树中给定深度的二叉树的节点数。例如,下面的树
有 1 个深度为 0 的节点(根节点)、2 个深度为 1 的节点、3 个深度为 2 的节点和 3 个深度为 3 的节点。
在我的程序中,二叉树表示为 形式的列表[value, left-child, right-child]
,其中左右孩子本身可以用相同的方式表示。例如,这里是上述树的表示:
[8, [3, [1, [], []],
[6, [4, [], []],
[7, [], []]]],
[10, [],
[14,
[13, [], []],
[]]]]
这是我到目前为止想出的:
nbNodes([_,_,_],1,0).
nbNodes([_,LC,RC],N2,D2) :-
nbNodes(LC,NL,D), nbNodes(RC,NR,D), N2 is NL+NR, D2 is D+1.
基于我对 Prolog 的有限理解,这意味着:
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.
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.
要获得更完整的图片,您需要深入研究 Prolog 对分辨率原理的(部分)实现。如果您想拥有一种更具声明性的 Prolog,请查看约束逻辑编程。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句