Inheritance Coq集继承

Inheritance Coq集继承,inheritance,coq,Inheritance,Coq,我已经从实数公理开始证明了许多定理,现在我想将自然数定义为实数的子集,并重用所有已证明的定理。怎样才能做到呢?这是一个人工MRE,将使用适当的coq设计实践进行编译: 01 (* CReal Definitions *) 02 Parameter CReal: Set. 03 Parameter creal_add : CReal -> CReal -> CReal. 04 Axiom creal_comm: forall x y:CReal, creal_add x y =

我已经从实数公理开始证明了许多定理,现在我想将自然数定义为实数的子集,并重用所有已证明的定理。怎样才能做到呢?这是一个人工MRE,将使用适当的coq设计实践进行编译:

01  (* CReal Definitions *)
02  Parameter CReal: Set.
03  Parameter creal_add : CReal -> CReal -> CReal.
04  Axiom creal_comm: forall x y:CReal, creal_add x y = creal_add y x.
05   
06  (* CNat Definitions *)
07  Parameter CNat: Set.
08  Theorem cnat_comm: forall x y:CNat, creal_add x y = creal_add y x.
09  Proof. exact creal_comm. Qed. (* Should be OK after subclassing *)
现在它抱怨O是CReal而不是CNat,因此,如果x被多态地解释为CReal,能够与其他CReal进行比较,并以一种漂亮而不复杂的方式应用CReal定理和公理,那将是一件好事

编辑

为了更清楚地说明我想要什么,下面是在正确的子类化之后不应该编译的代码:

11  (* CNat Positive *)
12  Parameter O : CReal.
13  Parameter cnat_succ : CNat -> CNat.
14  Axiom cnat_positive: forall (x : CNat), ~cnat_succ x=O.
15
16  (* CReal Wrong Theorem *)
17  Theorem creal_positive: forall x:CReal, ~cnat_succ x=O. (*Crash*)
18  Proof. exact cnat_positive. Qed. (*Also Crash*)

第17行和第18行应该崩溃的原因是,第17行在CReal上使用了cnat_succ,但cnat_succ仅为子类cnat定义,而在第18行中使用了一个cnat公理,它不应该被超类CReal看到。因此,超类公理和定理对于子类应该是可见的并适用于子类,而不是相反。

您必须证明您的
CNat
CReal
的子集同构,并且
CNat
操作是关闭的

这里有一个例子,你可以扩展到你喜欢的。我使用用于reals的
lra
策略证明了一个简单引理

我使用强制,这样就不必在任何地方手动插入注入函数
f
g
。它们在那里,但是用看不见的墨水。设置打印强制。如果您想查看它们


Require Import Reals.

Open Scope R.
Parameter (N:Type)(f:N->R) (g:R->N).
Parameter iso1: forall x, f (g x) = x.
Parameter iso2: forall x, g (f x) = x.
Coercion f : N>->R.
Coercion g : R>->N.

Parameter (n0 n1 : N) (nplus nmult : N->N->N) .
Parameter nzero : n0 = 0.
Parameter none : n1 = 1.
Parameter nplus_ok : forall a b:N, nplus a b  = a+b.
Parameter nmult_ok : forall a b:N, nmult a b  = a*b.

Set Printing Coercions.
Print nplus_ok.
(*  nplus_ok : forall a b : N, nplus a b = g (f a + f b)  *)
Unset Printing Coercions.

(* useful tactic to rewrite N to R *)
Ltac NtoR :=
  rewrite ?nplus_ok,  ?nmult_ok, ?nzero, ?none,  ?iso1;
  try apply f_equal.

Require Import Psatz.
Goal forall (a b c:N),
    (nplus a (nplus b c)) + nmult 1 (a+n1+c) = nplus (2*nplus c a) (nplus (n0+1) b).
  intros.
  NtoR.
  lra.
Qed.

最后,我找到了一个使用类型类的解决方案。这里是一个使用整数的自然数的扩展,它比使用自然数扩展实数更有意义,这些实数比前者更不专业(需要更少的公理):

01  (* Import Setoid for smart rewriting *)
02  Require Import Setoid.
03  
04  
05  (* -------------------------------------------------- *)
06  (* CNat Class *)
07  
08  
09  (* CNat Definition *)
10  Class CNat A := {
11    O: A;
12    succ: A->A;
13    add: A->A->A;
14    add_comm: forall x y:A, add x y = add y x
15  }.
16  
17  (* O Commutativity Lemma *)
18  Lemma O_SO `{CNat}: add O (succ O) = add (succ O) O.
19  Proof.
20    apply add_comm.                 (* Class axiom *)
21  Qed.
这就是CNat类定义及其O_SO引理。现在,CInt类定义、一些符号及其invO_O引理重用了CNat超类公理(add_comm公理)和定理(O_SO引理):

可以看出,子类可以使用超类的公理和定理。此外,符号和setoid智能重写可用于以漂亮的形式、类型安全和可扩展的方式演示定理

PD

如果您想对所有x:A使用
,您需要使用
可概化变量来参数化您的定理

48 Generalizable Variables A.
49 (* Commutative Additive Inverse Lemma *)
50 Lemma inv_inv `{CInt A}: forall x:A, ¯x±x=O.
51 Proof.
52   setoid_rewrite add_comm.
53   apply add_inv.
54 Qed.

这里你是在自然和实之间创建一个同构,而不是在自然和实的子集之间创建一个同构,不是吗?如果你告诉我如何使用实的子集而不是纯实的子集,这将得到解决。
N
这里是预期的“子集”。但是你是在定义实和该子集之间的同构。那样的话,如果我要为自然或那个子集证明一些东西,我也会为Reals证明它,这超出了我想要的真正继承的目的。你能不能用一两个例子来扩展你的问题,说明你想做什么,而你目前还不能做什么?
48 Generalizable Variables A.
49 (* Commutative Additive Inverse Lemma *)
50 Lemma inv_inv `{CInt A}: forall x:A, ¯x±x=O.
51 Proof.
52   setoid_rewrite add_comm.
53   apply add_inv.
54 Qed.