繁体   English   中英

如何为构造函数设置隐式参数

[英]How to set implicit parameters for constructor

与nostutter excersizes一起玩我发现了另一种奇怪的行为。 这是代码:

Inductive nostutter {X:Type} : list X -> Prop :=
| ns_nil : nostutter []
| ns_one : forall (x : X), nostutter [x]
| ns_cons: forall (x : X) (h : X) (t : list X), nostutter (h::t) -> x <> h -> nostutter (x::h::t).

Example test_nostutter_manual: not (nostutter [3;1;1;4]).
Proof.
  intro.
  inversion_clear H.
  inversion_clear H0.
  unfold not in H2.
  (* We are here *)
  specialize (H2 eq_refl).
  apply H2.
Qed.

展开后的状态是这样的:

1 subgoal (ID 229)

H1 : 3 <> 1
H : nostutter [1; 4]
H2 : 1 = 1 -> False
============================
False

当我运行specialize (H2 eq_refl). 在IndProp.v中加载其他逻辑基础文件,它可以工作。 不知何故,它理解它需要将“1”作为参数。 IndProp.v的标题是这样的:

Set Warnings "-notation-overridden,-parsing".
From LF Require Export Logic.
Require Import String.
Require Coq.omega.Omega.

当我将代码移动到另一个文件“nostutter.v”时,这个相同的代码给出了一个预期的错误:

术语“eq_refl”具有类型“RelationClasses.Reflexive Logic.eq”,而期望它具有类型“1 = 1”。

nostutter.v的标题:

Set Warnings "-notation-overridden,-parsing".
Require Import List.
Import ListNotations.
Require Import PeanoNat.
Import Nat.
Local Open Scope nat_scope.

我必须明确地向eq_refl添加一个参数: specialize (H2 (eq_refl 1)).

我认为这与专业化无关。 它是什么? 怎么修?

问题是导入PeanoNat.Nat

当您导入PeanoNat ,模块类型Nat进入范围,因此导入NatPeanoNat.Nat 如果您要导入Coq.Init.Nat ,则必须在导入PeanoNat之前导入PeanoNat ,或者使用Import Init.Nat.导入它Import Init.Nat.

为什么导入PeanoNat.Nat会导致这种情况的麻烦?

Arith / PeanoNat.v静态链接 )包含模块1 Nat 在该模块中,我们发现2个不寻常的外观

Include NBasicProp <+ UsualMinMaxLogicalProperties <+ UsualMinMaxDecProperties.

所有这些意味着包括NBasicPropUsualMinMaxLogicalPropertiesUsualMinMaxDecProperties中的每一个,这反过来意味着在那些模块中定义的所有内容都包含在当前模块中。 将这一行分成三个Include命令,我们可以找出哪一个正在重新定义eq_refl 原来是NBasicProp ,可以在这个文件中找到( 静态链接 )。 我们还没到那里:eq_refl的重新定义不在这里。 然而,我们看到的定义NBasicProp来讲NMaxMinProp

这导致我们进入NMaxMin.v,后者又将我们带到NSub.v,它将我们带到NMulOrder.v,它将我们带到NAddOrder.v,它将我们带到NOrder.v,它将我们带到NAdd.v,这导致我们到NBase.v,...

我会切到这里追逐。 最后,我们在最终结构/ Equality.v静态链接 )与模块BackportEq并最终赋予我们的重新定义eq_refl

Module BackportEq (E:Eq)(F:IsEq E) <: IsEqOrig E.
 Definition eq_refl := @Equivalence_Reflexive _ _ F.eq_equiv.
 Definition eq_sym := @Equivalence_Symmetric _ _ F.eq_equiv.
 Definition eq_trans := @Equivalence_Transitive _ _ F.eq_equiv.
End BackportEq.

这个定义的方式, eq_refl (没有任何参数)有类型Reflexive eq ,其中Reflexive是类

Class Reflexive (R : relation A) :=
  reflexivity : forall x : A, R x x.

(在Classes / RelationClasses.v中找到)

所以这意味着我们总是需要提供额外的参数来获得x = x类型的东西。 这里没有定义隐式参数。

为什么导入像PeanoNat.Nat这样的模块通常是个坏主意?

如果上面的野鹅追逐不够令人信服,那么我只想说像这样扩展和导入其他模块和模块类型的模块通常不是要导入的。 它们通常具有短名称(如NZNat ),因此您可以轻松访问要从中使用的任何定理,而无需键入长名称。 它们通常具有长链进口,因此包含大量物品。 如果您导入它们,那么现在大量的项目正在污染您的全局命名空间。 正如您在eq_refl看到的eq_refl ,这会导致您认为常见的常见事件。


  1. 在这次冒险中遇到的大多数模块都属于“模块类型/仿函数”。 可以说,他们很难完全理解,但可以在这里找到一个简短的指南。

  2. 我的调查是通过在CoqIDE中打开文件并运行命令Locate eq_refl. (或者更好的是,ctrl + shift + L)在可能从其他地方导入的任何东西之后。 Locate还可以告诉您从哪里导入常量。 我希望有一种更简单的方法来查看模块类型中的导入路径,但我不这么认为。 您可能会猜测我们最终会根据覆盖的eq_refl的类型进入eq_refl ,但这并不精确。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM