Coq 在使用强制类型定义构造函数时遇到困难

Coq difficulties in defining constructors using coerced types

定义

我正致力于在 Coq 中形式化类型化的 lambda 演算,并且为了使符号易于管理,我开始非常依赖强制转换。但是,我 运行 遇到了一些看起来很奇怪的困难。

现在我正在尝试使用以下类型:

实际定义都在下面给出,除了ctx_join在下一个块中给出

(* Imports *)
Require Import lang_spec.
From Coq Require Import MSets.
Require Import List.
Import ListNotations.

Module VarSet := Make(Nat_as_OT).

Inductive Judgement : Type :=
| judge (v : var) (t : type)
.

Definition ty_ctx := (list Judgement).

Definition disj_vars (s1 s2 : VarSet.t) := VarSet.Empty (VarSet.inter s1 s2).

我经常想做类似 "this var does not appear in the set of vars bound by ty_ctx" 的陈述,为此我在下面的这些类型之间设置了一堆强制转换。


(* Functions to convert between the different types listed above *)

Fixpoint var_to_varset (v : var) : VarSet.t :=
  VarSet.singleton v.
Coercion var_to_varset : var >-> VarSet.t.

Fixpoint bound_variables (g : ty_ctx) : VarSet.t :=
  match g with
  | nil => VarSet.empty
  | cons (judge v _) g' =>VarSet.union (VarSet.singleton v) (bound_variables g')
  end.
Coercion bound_variables : ty_ctx >-> VarSet.t.

Inductive ctx_join :=
| join_single (g : ty_ctx)
| join_double (g1 g2 : ty_ctx)
              (disjoint_proof : disj_vars g1 g2)
.

Fixpoint coerce_ctx_join (dj : ctx_join) : ty_ctx :=
  match dj with
  | join_single g => g
  | join_double g1 g2 _ => g1 ++ g2
  end.
Coercion coerce_ctx_join : ctx_join >-> ty_ctx.

Fixpoint coerce_judgement_to_ty_ctx (j : Judgement) : ty_ctx :=
  cons j nil.
Coercion coerce_judgement_to_ty_ctx : Judgement >-> ty_ctx.


您会注意到 ctx_join 的定义依赖于将其参数从 ty_ctx 强制转换为 VarSet

我制定了转换层次结构只是为了让事情更清楚

问题

我想用下面的构造函数定义一个归纳类型

Inductive expr_has_type : ty_ctx -> nat -> type -> Prop :=
(* General Expressions *)
| ty_var (g : ty_ctx) (x : var) (t : type) (xfree : disj_vars x g)
  : expr_has_type (join_double (judge x t) g xfree) x t
.

问题是当我这样做时,出现以下错误:

Error:
In environment
expr_has_type : ty_ctx -> nat -> type -> Prop
g : ty_ctx
x : var
t : type
xfree : disj_vars x g
The term "xfree" has type "disj_vars x g" while it is expected to have type
 "disj_vars (judge x t) g" (cannot unify "VarSet.In a (VarSet.inter (judge x t) g)" and
"VarSet.In a (VarSet.inter x g)").

但是,如果我将 xfree 的类型更改为 disj_vars (VarSet.singleton x) g,那么定义就可以正常工作了!这看起来很奇怪,因为 disj_vars 仅在 VarSet 上定义,因此似乎 x 应该自动转换为 VarSet.singleton x 因为这就是强制转换的设置方式.

更奇怪的是,如果我不设置从 vars 到 varsets 的强制转换,那么 Coq 会正确地抱怨将 dis_vars 应用于 var 而不是 VarSet.所以强制肯定是在做某事

有人可以向我解释为什么第一个定义失败吗?考虑到我设置的强制转换,对我来说,上面的所有定义应该是等价的

备注

xfree 的类型更改为 disj_vars (judge x t) g 也修复了错误。这看起来也很奇怪,因为为了能够将 disj_vars 应用到 j := (judge x t),它首先需要通过 cons j nil 强制到 ty_ctx,然后到 VarSet 通过 bound_variables,它应该产生一个只包含 xVarSet(相当于 VarSet.singleton x?)。所以这个强制链似乎很顺利,而另一个虽然更简单但失败了

如果您使用 Set Printing Coercions.,错误消息将提供更多有关问题的信息:

The term "xfree" has type "disj_vars (var_to_varset x) (bound_variables g)"
while it is expected to have type
 "disj_vars (bound_variables (coerce_judgement_to_ty_ctx (judge x t)))
    (bound_variables g)"

问题是 xVarSet.t 的强制转换等于 Var.singleton x,而 judge 中的强制转换减少到 VarSet.union (VarSet.singleton x) VarSet.empty。虽然这两者在命题上是相等的,但在判断上它们并不相等,所以就 Coq 而言,它提出的术语是错误类型的。