Coq 使用';展开';在归纳的递归步骤内的不动点
我试图在coq中证明一些东西,同样的问题不断出现; 我想在归纳的递归(不是零)步骤中展开不动点的定义。“展开”按预期工作,下面是一个示例: 展开列表反转(rev)定义之前:Coq 使用';展开';在归纳的递归步骤内的不动点,coq,coq-tactic,Coq,Coq Tactic,我试图在coq中证明一些东西,同样的问题不断出现; 我想在归纳的递归(不是零)步骤中展开不动点的定义。“展开”按预期工作,下面是一个示例: 展开列表反转(rev)定义之前: n : nat l' : natlist IHl' : rev (rev l') = l' ============================ rev (rev (n :: l')) = n :: l' 之后: n : nat l' : natlist IHl' : rev (rev
n : nat
l' : natlist
IHl' : rev (rev l') = l'
============================
rev (rev (n :: l')) = n :: l'
之后:
n : nat
l' : natlist
IHl' : rev (rev l') = l'
============================
(fix rev (l : natlist) : natlist := match l with
| [ ] => [ ]
| h :: t => rev t ++ [h]
end)
((fix rev (l : natlist) : natlist := match l with
| [ ] => [ ]
| h :: t => rev t ++ [h]
end) l' ++ [n]) = n :: l'
到目前为止还不错。现在,我希望siml
能够找出我在归纳法的非零情况下,因为n::l'
永远不可能是零,
并简化匹配的nil情况([]=>[]
),只保留定义中的非nil部分
不幸的是,它并没有隐式地做到这一点。如何使递归不动点定义的展开
与归纳很好地结合起来?如何获得:
n : nat
l' : natlist
IHl' : rev (rev l') = l'
============================
rev (rev l' ++ [n]) = n :: l'
根据内部rev
的rev
定义
注意:列表的使用与此无关,相同的技术可用于任何归纳定义的类型
编辑:导致After状态的版本和证明的定义
您的
After:
基本上是rev(rev l'+[n])
(展开rev
),这意味着您希望看到发生的减少已经发生。现在你可能想证明一个类似于rev(xs++ys)=revys++revxs的辅助引理,请提交一个。当我们可以一步一步地通过证明并尝试不同的事情时,回答起来就容易多了。添加了rev
的定义以及导致After状态的证明。当然,我已经证明了这一点,但这个证明被用作示例。我真正想要的是减少从rev
定义中展开的讨厌的match
,因为模式匹配的nil情况是不可能的。如果我为所有n:nat,l:natlist,n::l~=[]
证明,那该怎么办?但是从cons
的定义来看,这应该是显而易见的。正如我所说:它已经被简化了。如果您尝试fold rev
,您将看到它现在已减少到rev(rev l'+[n])
。是的!折叠是我想要的!这是超级反直觉的顺便说一句,证明的关键是open rev。折叠版本代码>,读起来好像什么都没做。比如说,为什么这不是默认情况下siml
尝试的第一个策略之一呢?siml
取而代之的是unfold rev;fold rev
在我的机器上确实适用于。我深入研究了一下,似乎有一个很好的理由表明Coq不允许对递归匹配定义求值,即使输入将明显匹配非nil分支。在我的示例中,n::l'
永远不能是nil
,但是如果在哪里计算匹配并去掉nil
分支,递归就没有退出条件,可能会导致无限循环。
Fixpoint rev (l:natlist) : natlist :=
match l with
| nil => nil
| h :: t => rev t ++ [h]
end.
Theorem rev_involutive : forall l : natlist,
rev (rev l) = l.
Proof.
intros l. induction l as [| n l'].
- reflexivity.
- unfold rev.