请考虑以下一对相互递归的Coq数据类型,它们代表非空Forest
的{{1}}。 Tree
中的每个Branch
都有一个额外的布尔值标志,我们可以使用Tree
提取该标志。
isOK
现在,如果忽略此布尔值标志,我们可以编写一对映射函数,以将函数应用于Inductive Forest a : Type
:= Empty : Forest a
| WithTree : Tree a -> Forest a -> Forest a
with Tree a : Type
:= Branch : bool -> a -> Forest a -> Tree a.
Arguments Empty {_}.
Arguments WithTree {_} _ _.
Arguments Branch {_} _ _ _.
Definition isOK {a} (t : Tree a) : bool :=
match t with
| Branch ok _ _ => ok
end.
或Forest
中的每个值,并且可以正常工作:
Tree
但是,假设布尔值表示某种有效性检查,这在实际代码中会更加复杂。因此,我们首先检查布尔值,并且仅在必要时才实际递归。这意味着我们具有三个相互递归函数,但是其中之一只是在进行工作。不幸的是,这行不通:
Fixpoint mapForest_always {a} (f : a -> a) (ts0 : Forest a) {struct ts0} : Forest a :=
match ts0 with
| Empty => Empty
| WithTree t ts => WithTree (mapTree_always f t) (mapForest_always f ts)
end
with mapTree_always {a} (f : a -> a) (t : Tree a) {struct t} : Tree a :=
match t with
| Branch ok x ts => Branch ok (f x) (mapForest_always f ts)
end.
问题是Fail Fixpoint mapForest_bad {a} (f : a -> a) (ts0 : Forest a) {struct ts0} : Forest a :=
match ts0 with
| Empty => Empty
| WithTree t ts => WithTree (mapTree_bad f t) (mapForest_bad f ts)
end
with mapTree_bad {a} (f : a -> a) (t : Tree a) {struct t} : Tree a :=
if isOK t
then mapOKTree_bad f t
else t
with mapOKTree_bad {a} (f : a -> a) (t : Tree a) {struct t} : Tree a :=
match t with
| Branch ok x ts => Branch ok (f x) (mapForest_bad f ts)
end.
调用了实际上不是更小的参数的mapTree_bad
。
除了…mapOKTree_bad
的所有操作之外,还需要进行一些预处理。此将总是终止,但Coq看不到。为了说服终止检查器,我们可以改为定义mapOKTree_bad
,它是相同的,但是是本地mapOKTree_good
绑定;然后,终止检查器将查看let
绑定,并允许我们定义let
和mapForest_good
。如果我们想获得mapTree_good
,则可以在定义了相互递归函数后使用简单的旧定义,该函数的主体与mapOKTree_good
绑定相同:
let
这行得通,但是并不漂亮。有什么方法可以说服Coq的终止检查器接受Fixpoint mapForest_good {a} (f : a -> a) (ts0 : Forest a) {struct ts0} : Forest a :=
match ts0 with
| Empty => Empty
| WithTree t ts => WithTree (mapTree_good f t) (mapForest_good f ts)
end
with mapTree_good {a} (f : a -> a) (t : Tree a) {struct t} : Tree a :=
let mapOKTree_good {a} (f : a -> a) (t : Tree a) : Tree a :=
match t with
| Branch ok x ts => Branch ok (f x) (mapForest_good f ts)
end in
if isOK t
then mapOKTree_good f t
else t.
Definition mapOKTree_good {a} (f : a -> a) (t : Tree a) : Tree a :=
match t with
| Branch ok x ts => Branch ok (f x) (mapForest_good f ts)
end.
变体,还是_bad
诀窍是我所拥有的最好方法?像_good
或Program Fixpoint
这样对我有用的命令也是完全合理的解决方案。
答案 0 :(得分:3)
非常部分的答案:我们可以在定义mapOKTree_good
之前,通过由mapForest_good
参数化的中间定义来重构Definition mapOKTree_good_ {a} mapForest_good
(f : a -> a) (t : Tree a) : Tree a :=
match t with
| Branch ok x ts => Branch ok (f x) (mapForest_good f ts)
end.
Fixpoint mapForest_good {a} (f : a -> a) (ts0 : Forest a) {struct ts0} : Forest a :=
match ts0 with
| Empty => Empty
| WithTree t ts => WithTree (mapTree_good f t) (mapForest_good f ts)
end
with mapTree_good {a} (f : a -> a) (t : Tree a) {struct t} : Tree a :=
if isOK t
then mapOKTree_good_ mapForest_good f t
else t.
Definition mapOKTree_good {a} := @mapOKTree_good_ a mapForest_good.
的两个定义。
Events.insert({ 'start': new Date(2018, 9, 5, 7, 0, 0, 0) });