通过一些教程,我发现了一些像flatten这样的高级递归程序。我试图谷歌找到涉及多次递归(头尾)的类似例子,但无法得到我需要的结果。
你能否推断一些涵盖高级列表重复的谓词或教程(头部,尾部)?
答案 0 :(得分:4)
为了扩展@hardmath所说的内容,让我们来看看列表的定义:
[]
[Head|Tail]
这是一个递归数据结构的原因是Tail
也是一个列表。因此,当您看到[1,2,3]
时,您也会看到[1|[2|[3|[]]]]
。让我们证明一下:
?- X = [1|[2|[3|[]]]].
X = [1, 2, 3].
因此,更多“高级”递归形式是涉及更复杂的递归数据类型或更复杂计算的形式。大多数人接触的下一个递归数据类型是二叉树,二叉树具有很好的属性,它们每个节点有两个分支,所以让我们看一下树。
首先,我们需要一个很好的定义,比如列表中的定义。我提出以下建议:
empty
tree(LeftBranch, Value, RightBranch)
现在让我们创建一些示例树,以了解它们的外观:
% this is like the empty list: no data
empty
% this is your basic tree of one node
tree(empty, 1, empty)
% this is a tree with two nodes
tree(tree(empty, 1, empty), 2, empty).
在结构上,最后一个例子可能看起来像这样:
2
/
1
现在让我们用几个级别做一个更全面的例子。让我们构建这棵树:
10
/ \
5 9
/ \ / \
4 6 7 14
在我们的Prolog语法中,它看起来像这样:
tree(tree(tree(empty, 4, empty), 5, tree(empty, 6, empty)),
10,
tree(tree(empty, 7, empty), 9, tree(empty, 14, empty)))
我们想要的第一件事就是增加树的大小。与列表一样,我们需要考虑我们的基本案例,然后考虑我们的归纳案例。
% base case
tree_size(empty, 0).
% inductive case
tree_size(tree(Left, _, Right), Size) :-
tree_size(Left, LeftSize),
tree_size(Right, RightSize),
Size is LeftSize + RightSize + 1.
为了比较,让我们看一下列表长度:
% base case
length([], 0).
% inductive case
length([_|Rest], Length) :-
length(Rest, LengthOfRest),
Length is LengthOfRest + 1.
编辑:@ false指出虽然上述内容很直观,但可以通过将归纳案例更改为:
来生成具有更好逻辑属性的版本length([_|Rest], Length) :-
length(Rest, LengthOfRest),
succ(LengthOfRest, Length).
因此,您可以通过比较这两者来清楚地看到递归处理数据结构的标志:
您编写规则的基础来处理基本情况。
这一步通常很明显;在长度或大小的情况下,您的数据结构将具有一个空的基本案例,因此您只需将零与该案例相关联。
你写下你的规则的归纳步骤。
归纳步骤采用数据结构的递归情况,并处理该案例添加的任何内容,并将其与递归调用规则的结果相结合,以处理数据结构的“其余部分”。
因为列表只在一个方向递归,所以在大多数列表处理规则中只有一个递归调用。因为树有两个分支,所以可以有一个或两个分支,具体取决于您是需要处理整个树还是只需沿着一条路径行进。列表和树有效地具有两个“构造函数”,因此大多数规则将具有两个主体,一个用于处理空情况,一个用于处理诱导情况。更复杂的结构,例如语言语法,可以有两种以上的基本模式,通常你可以单独处理所有这些模式,或者你只是特别寻找一种模式。
作为练习,您可能需要尝试撰写search
,insert
,height
,balance
或is_balanced
以及其他各种树查询以获取更多信息熟悉这个过程。