Tree 序言:使用纯递归只计算父节点的直接子节点

Tree 序言:使用纯递归只计算父节点的直接子节点,tree,prolog,parent,children,Tree,Prolog,Parent,Children,在Prolog中,是否可以在不使用retract/aggregate等的情况下使用递归计算父节点的直接子节点数 例如,假设我们有以下内容: parent(p1, child_node1). parent(p1, child_node2). parent(p1, child_node3). parent(p1, child_node4). parent(child_node1, another_node1). parent(child_node1, another_node2). parent(

Prolog中,是否可以在不使用
retract
/
aggregate
等的情况下使用递归计算父节点的直接子节点数

例如,假设我们有以下内容:

parent(p1, child_node1).
parent(p1, child_node2).
parent(p1, child_node3).
parent(p1, child_node4).

parent(child_node1, another_node1).
parent(child_node1, another_node2).
parent(child_node2, another_node3).
parent(child_node2, another_node4).
parent(child_node3, another_node5).
parent(child_node3, another_node6).
parent(child_node4, another_node7).
parent(child_node4, another_node8).

我们如何使用递归计算p1具有4个直接子节点的节点数?

一个简单的解决方案是维护一个我们已经看到的子节点列表,每次查询一个尚未成为该列表成员的子节点。每次我们找到一个子对象时,我们都会递归并将该子对象添加到列表中。如果我们再也找不到这样的孩子,我们可以将结果与迄今为止获得的孩子统一起来

count_children(Parent, N) :-
    count_children(Parent, [], 0, N).

count_children(Parent, L, N0, N) :-
    (parent(Parent, C), \+member(C, L))
    -> (N1 is N0+1, count_children(Parent, [C|L], N1, N))
    ; N = N0.
例如:

?- count_children(p1, N).
N = 4.

?- count_children(child_node1, N).
N = 2.

?- count_children(child_node2, N).
N = 2.

?- count_children(child_node3, N).
N = 2.

?- count_children(child_node4, N).
N = 2.

?- count_children(another_node1, N).
N = 0.
但是,如果父级未统一,它将与第一个父级统一,并在获得第一个结果后停止:

?- count_children(P, N).
P = p1,
N = 4.

我把它作为一种练习,让它与所有可能的父母统一起来。

一个简单的解决方案是维护一个我们已经看到的孩子的列表,每次查询一个孩子时,这个孩子还不是该列表的成员。每次我们找到一个子对象时,我们都会递归并将该子对象添加到列表中。如果我们再也找不到这样的孩子,我们可以将结果与迄今为止获得的孩子统一起来

count_children(Parent, N) :-
    count_children(Parent, [], 0, N).

count_children(Parent, L, N0, N) :-
    (parent(Parent, C), \+member(C, L))
    -> (N1 is N0+1, count_children(Parent, [C|L], N1, N))
    ; N = N0.
例如:

?- count_children(p1, N).
N = 4.

?- count_children(child_node1, N).
N = 2.

?- count_children(child_node2, N).
N = 2.

?- count_children(child_node3, N).
N = 2.

?- count_children(child_node4, N).
N = 2.

?- count_children(another_node1, N).
N = 0.
但是,如果父级未统一,它将与第一个父级统一,并在获得第一个结果后停止:

?- count_children(P, N).
P = p1,
N = 4.

我把它作为一种练习,让它与所有可能的父母结合起来。

为什么不与
findall/3
结合呢?使用递归将使程序效率低下,因为它基本上每次都会在求值树上进行另一次遍历。我只关心是否(以及如何)仅使用纯递归就可以实现它,也就是说。当然,有更有效的方法来实现这一点。你自己想出了一个草图(或尝试)来解决这个问题吗?我可以通过使用
retract
/
aggregate\u all
findall/3
中的一个来实现这一点,但没有它们,我就没有多少成功。我目前的想法是创建一个列表,并在其中填充子项,然后计算其长度。然而,作为Prolog的新手,我觉得我错过了一些东西,不确定如何确保我不会永远在同一个孩子身上循环。为什么不使用
findall/3
?使用递归将使程序效率低下,因为它基本上每次都会在求值树上进行另一次遍历。我只关心是否(以及如何)仅使用纯递归就可以实现它,也就是说。当然,有更有效的方法来实现这一点。你自己想出了一个草图(或尝试)来解决这个问题吗?我可以通过使用
retract
/
aggregate\u all
findall/3
中的一个来实现这一点,但没有它们,我就没有多少成功。我目前的想法是创建一个列表,并在其中填充子项,然后计算其长度。然而,作为Prolog的新手,我觉得我错过了一些东西,不确定如何确保我不会永远在同一个孩子身上循环。非常感谢这个解释,它为我澄清了这件事。非常感谢这个解释,它为我澄清了这件事。