与Agda不同,Coq倾向于将证明与功能分开。 Coq给出的策略非常适合编写证明,但我想知道是否有办法复制一些Agda模式功能。
具体来说,我想:
?
或Haskell的_
,我可以在编写时省略函数的一部分,并且(希望)让Coq告诉我需要放在那里的类型?
块,并且它将为所需参数创建新的?
块match
时,让Coq自动写入扩展可能的分支(如Agda模式中的C-c C-a)这可能在CoqIde或Proof General中吗?
答案 0 :(得分:6)
正如ejgallego在评论中所建议的,你可以(几乎)这样做。有company-coq工具,可以在ProofGeneral上工作。
让我演示如何使用company-coq和map
策略实现refine
函数。从
Fixpoint map {A B} (f : A -> B) (xs : list A) : list B.
键入refine ().
,然后将光标放在parens中并键入 Cc Ca RET list RET - 它会在填充了孔的列表中插入match
表达式手动(让我们填写列表名称和基本情况)。
Fixpoint map {A B} (f : A -> B) (xs : list A) : list B.
refine (match xs with
| nil => nil
| cons x x0 => cons _ _
end).
要完成此操作,我们会将x0
重命名为tl
并提供递归案例exact (map A B f tl).
:
Fixpoint map {A B} (f : A -> B) (xs : list A) : list B.
refine (match xs with
| nil => nil
| cons x tl => cons _ _
end).
exact (f x).
exact (map A B f tl).
Defined.
还有一个有用的键盘快捷键 C-c C-a C-x ,它有助于将当前目标提取到单独的引理/辅助函数中。
答案 1 :(得分:5)
让我教你一个奇怪的伎俩。它可能不是你所有问题的答案,但它可能会有所帮助,至少在概念上是这样。
让我们实现自然数的加法,后者由
给出Inductive nat : Set :=
| zero : nat
| suc : nat -> nat.
您可以尝试通过策略来编写添加内容,但这种情况会发生。
Theorem plus' : nat -> nat -> nat.
Proof.
induction 1.
plus' < 2 subgoals
============================
nat -> nat
subgoal 2 is:
nat -> nat
你无法看到你在做什么。
诀窍是仔细观察你正在做的事情。我们可以引入一个无偿的依赖类型,克隆nat
。
Inductive PLUS (x y : nat) : Set :=
| defPLUS : nat -> PLUS x y.
我们的想法是PLUS x y
是“计算plus x y
的方式”。我们需要一个投影,允许我们提取这种计算的结果。
Theorem usePLUS : forall x y, PLUS x y -> nat.
Proof.
induction 1.
exact n.
Defined.
现在我们已准备好通过证明进行编程。
Theorem mkPLUS : forall x y, PLUS x y.
Proof.
mkPLUS < 1 subgoal
============================
forall x y : nat, PLUS x y
目标的结论向我们展示了我们当前的左手边和背景。 Agda中C-c C-c
的类似物是......
induction x.
mkPLUS < 2 subgoals
============================
forall y : nat, PLUS zero y
subgoal 2 is:
forall y : nat, PLUS (suc x) y
你可以看到它完成了案件分割!让我们敲掉基本案例。
intros y.
exact (defPLUS zero y y).
调用PLUS的构造函数就像写一个方程式。想象一下在第三个参数之前的=
符号。对于步骤情况,我们需要进行递归调用。
intros y.
eapply (fun h => (defPLUS (suc x) y (suc (usePLUS x y h)))).
要进行递归调用,我们使用我们想要的参数调用usePLUS
,这里x
和y
,但是我们抽象了第三个参数,这是实际的解释计算它。我们只剩下那个子目标,实际上是终止检查。
mkPLUS < 1 subgoal
x : nat
IHx : forall y : nat, PLUS x y
y : nat
============================
PLUS x y
现在,您不是使用Coq的防范检查,而是使用......
auto.
...检查归纳假设是否涵盖递归调用。我们
Defined.
我们有一个工人,但我们需要一个包装器。
Theorem plus : nat -> nat -> nat.
Proof.
intros x y.
exact (usePLUS x y (mkPLUS x y)).
Defined.
我们准备好了。
Eval compute in (plus (suc (suc zero)) (suc (suc zero))).
Coq < = suc (suc (suc (suc zero)))
: nat
您拥有交互式构建工具。您可以对其进行游戏,通过使类型更具信息性来向您展示您正在解决的问题的相关细节。由此产生的校对脚本......
Theorem mkPLUS : forall x y, PLUS x y.
Proof.
induction x.
intros y.
exact (defPLUS zero y y).
intros y.
eapply (fun h => (defPLUS (suc x) y (suc (usePLUS x y h)))).
auto.
Defined.
...明确说明它构建的程序。你可以看到这是定义的补充。
如果你为程序构建自动化这个设置,然后在界面上显示你正在构建的程序和关键的问题简化策略,你会得到一个名为Epigram 1的有趣的小编程语言。