简体   繁体   English

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

[英]How to set implicit parameters for constructor

Playing with nostutter excersizes I found another odd behaviour. 与nostutter excersizes一起玩我发现了另一种奇怪的行为。 Here is the code: 这是代码:

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.

Status after unfold is this: 展开后的状态是这样的:

1 subgoal (ID 229)

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

When I run specialize (H2 eq_refl). 当我运行specialize (H2 eq_refl). inside IndProp.v that loads other Logical foundations files, it works. 在IndProp.v中加载其他逻辑基础文件,它可以工作。 Somehow it understands that it needs to put "1" as a parameter. 不知何故,它理解它需要将“1”作为参数。 Header of IndProp.v is this: IndProp.v的标题是这样的:

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

When I move the code into another file "nostutter.v", this same code gives an expected error: 当我将代码移动到另一个文件“nostutter.v”时,这个相同的代码给出了一个预期的错误:

The term "eq_refl" has type "RelationClasses.Reflexive Logic.eq" while it is expected to have type "1 = 1". 术语“eq_refl”具有类型“RelationClasses.Reflexive Logic.eq”,而期望它具有类型“1 = 1”。

Header of nostutter.v: nostutter.v的标题:

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

I have to explicitly add a parameter to eq_refl : specialize (H2 (eq_refl 1)). 我必须明确地向eq_refl添加一个参数: specialize (H2 (eq_refl 1)).

I think it's not related specifically to specialize. 我认为这与专业化无关。 What is it? 它是什么? How to fix? 怎么修?

The problem is importing PeanoNat.Nat . 问题是导入PeanoNat.Nat

When you import PeanoNat , the module type Nat comes into scope, so importing Nat brings in PeanoNat.Nat . 当您导入PeanoNat ,模块类型Nat进入范围,因此导入NatPeanoNat.Nat If you meant to import Coq.Init.Nat , you'll either have to import it before importing PeanoNat , or import it with Import Init.Nat. 如果您要导入Coq.Init.Nat ,则必须在导入PeanoNat之前导入PeanoNat ,或者使用Import Init.Nat.导入它Import Init.Nat. .

Why does importing PeanoNat.Nat cause trouble in this case? 为什么导入PeanoNat.Nat会导致这种情况的麻烦?

Arith/PeanoNat.v ( static link ) contains the module 1 Nat . Arith / PeanoNat.v静态链接 )包含模块1 Nat Inside that module, we find 2 the unusual looking line 在该模块中,我们发现2个不寻常的外观

Include NBasicProp <+ UsualMinMaxLogicalProperties <+ UsualMinMaxDecProperties.

All this means is that each of NBasicProp , UsualMinMaxLogicalProperties and UsualMinMaxDecProperties are included, which in turn means that everything defined in those modules is included in the current module. 所有这些意味着包括NBasicPropUsualMinMaxLogicalPropertiesUsualMinMaxDecProperties中的每一个,这反过来意味着在那些模块中定义的所有内容都包含在当前模块中。 Separating this line out into three Include commands, we can figure out which one is redefining eq_refl . 将这一行分成三个Include命令,我们可以找出哪一个正在重新定义eq_refl It turns out to be NBasicProp , which is found in this file ( static link ). 原来是NBasicProp ,可以在这个文件中找到( 静态链接 )。 We're not quite there yet: the redefinition of eq_refl isn't here. 我们还没到那里:eq_refl的重新定义不在这里。 However, we see the definition of NBasicProp in terms of NMaxMinProp . 然而,我们看到的定义NBasicProp来讲NMaxMinProp

This leads us to NMaxMin.v, which in turn leads us to NSub.v, which leads us to NMulOrder.v, which leads us to NAddOrder.v, which leads us to NOrder.v, which leads us to NAdd.v, which leads us to NBase.v, ... 这导致我们进入NMaxMin.v,后者又将我们带到NSub.v,它将我们带到NMulOrder.v,它将我们带到NAddOrder.v,它将我们带到NOrder.v,它将我们带到NAdd.v,这导致我们到NBase.v,...

I'll cut to the chase here. 我会切到这里追逐。 Eventually we end up in Structures/Equality.v ( static link ) with the module BackportEq which finally gives us our redefinition of eq_refl . 最后,我们在最终结构/ 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.

The way this is defined, eq_refl (without any arguments) has type Reflexive eq , where Reflexive is the class 这个定义的方式, eq_refl (没有任何参数)有类型Reflexive eq ,其中Reflexive是类

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

(found in Classes/RelationClasses.v) (在Classes / RelationClasses.v中找到)

So that means that we'll always need to supply an extra argument to get something of type x = x . 所以这意味着我们总是需要提供额外的参数来获得x = x类型的东西。 There are no implicit arguments defined here. 这里没有定义隐式参数。

Why is importing modules like PeanoNat.Nat generally a bad idea? 为什么导入像PeanoNat.Nat这样的模块通常是个坏主意?

If the wild goose chase above wasn't convincing enough, let me just say that modules like this one, which extend and import other modules and module types, are often not meant to be imported. 如果上面的野鹅追逐不够令人信服,那么我只想说像这样扩展和导入其他模块和模块类型的模块通常不是要导入的。 They often have short names (like N , Z or Nat ) so any theorem you want to use from them is easily accessible without having to type out a long name. 它们通常具有短名称(如NZNat ),因此您可以轻松访问要从中使用的任何定理,而无需键入长名称。 They usually have a long chain of imports and thus contain a vast number of items. 它们通常具有长链进口,因此包含大量物品。 If you import them, now that vast number of items is polluting your global namespace. 如果您导入它们,那么现在大量的项目正在污染您的全局命名空间。 As you saw with eq_refl , that can cause unexpected behavior with what you thought was a familiar constant. 正如您在eq_refl看到的eq_refl ,这会导致您认为常见的常见事件。


  1. Most of the modules encountered in this adventure are of the "module type/functor" variety. 在这次冒险中遇到的大多数模块都属于“模块类型/仿函数”。 Suffice to say, they're difficult to understand fully, but a short guide can be found here . 可以说,他们很难完全理解,但可以在这里找到一个简短的指南。

  2. My sleuthing was done by opening files in CoqIDE and running the command Locate eq_refl. 我的调查是通过在CoqIDE中打开文件并运行命令Locate eq_refl. (or better yet, ctrl+shift+L) after anything that might import from elsewhere. (或者更好的是,ctrl + shift + L)在可能从其他地方导入的任何东西之后。 Locate can also tell you where a constant was imported from. Locate还可以告诉您从哪里导入常量。 I wish there were an easier way to see the path of imports in module types, but I don't think so. 我希望有一种更简单的方法来查看模块类型中的导入路径,但我不这么认为。 You could guess that we'd end up in Coq.Classes.RelationClasses based on the type of the overwritten eq_refl , but that isn't as precise. 您可能会猜测我们最终会根据覆盖的eq_refl的类型进入eq_refl ,但这并不精确。

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

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