如何用SSReflect更优雅地完成Coq证明?
Coq SSReflect证明优化问题与修正方案
以下针对你给出的三个Coq引理证明,逐一指出冗余点并给出SSReflect风格的优化方案,同时说明核心战术要点:
引理L1:简化假设应用与解构
原证明疑问
似乎可以不用先移动变量,直接将H2应用到H1中
优化后证明
Lemma L1: forall A B C, A -> (A -> B /\ C) -> C. Proof. move => A B C H1 H2. apply: H2 in H1; destruct H1 as [_ Hc]. done. Qed.
或更紧凑的版本:
Lemma L1: forall A B C, A -> (A -> B /\ C) -> C. Proof. move => A B C H1 H2; exact: (proj2 (H2 H1)). Qed.
核心要点
- SSReflect的
apply:战术可直接指定要应用的函数,in子句用于修改上下文假设,无需额外步骤 - 解构
B /\ C时,可通过[_ Hc]只保留需要的C分量,忽略无用的B - 若目标明确,可直接用
exact:结合投影函数proj2一步完成证明
引理L2:消除冗余断言,直接传递参数
原证明疑问
觉得没必要单独构造
H,应该有更直接的apply方式
优化后证明
Lemma L2: forall A Q, (forall x, (exists y, x + y = y + x) -> A) -> Q -> A. Proof. move => A _ T _. apply: (T 2); exists 0; lia. Qed.
核心要点
- SSReflect的
apply:支持直接传递函数参数(此处T 2生成(exists y, 2+y=y+2) -> A) - 无需单独断言
H,直接在apply:后链式构造存在性证明,一步完成前提推导 lia自动处理加法交换律的数值验证,省去手动展开步骤
引理divides_by_2_by_3_means_by_6:复用库引理,简化分情况
原证明疑问
不确定创建子目标的最佳方式,以及添加事实到上下文的正确方法
优化后证明(SSReflect风格+库引理复用)
Lemma divides_by_2_by_3_means_by_6 : forall z p q, z = 2 * p -> z = 3 * q -> exists n, z = 6 * n. Proof. move => z p q P Q. case: (Nat.even_odd_spec q) => [x Hx | x Hx]. - exists x; rewrite Q Hx; lia. - rewrite Hx Q in P; lia. Qed.
或更简洁的数论直接推导:
Lemma divides_by_2_by_3_means_by_6 : forall z p q, z = 2 * p -> z = 3 * q -> exists n, z = 6 * n. Proof. move => z p q -> ->; lia. Qed.
核心要点
- 复用库引理:无需手动证明奇偶性,直接调用
Nat.even_odd_spec(Coq标准库已提供的自然数奇偶分情况引理) - SSReflect的
case:战术:直接对引理结果进行分情况分析,无需先将事实移动到上下文 - 模式匹配替换:
move => z p q -> ->直接将z=2p和z=3q替换到上下文,简化目标 - 自动化工具:
lia可直接处理此类线性数论存在性证明,无需手动分情况(适合快速验证)
内容的提问来源于stack exchange,提问作者lindvv
相关产品推荐
相关产品推荐

