我对Coq中的模块不是很熟悉,但是我在最近的一个问题中提出了这个问题。我有以下代码。
Module Type Sig.
Parameter n : nat.
Definition n_plus_1 := n + 1.
End Sig.
Module ModuleInstance <: Sig.
Definition n := 3.
End ModuleInstance.
当我尝试运行n_plus_1
时,Coq抱怨End ModuleInstance
的定义。我不确定这是否是使用模块的正确方法,但我希望它只使用签名中的定义,它是一个完整的定义,不需要任何其他信息。有可能吗?
答案 0 :(得分:1)
您需要将您的定义放入单独的&#34;模块函数&#34; (基本上是模块级函数:这些是将其他模块作为参数的模块),因此Sig
仅包含参数:
Module Type Sig.
Parameter n : nat.
End Sig.
(* this is the module functor *)
Module SigUtils (S:Sig).
Definition n_plus_1 := S.n + 1.
End SigUtils.
Module ModuleInstance <: Sig.
Definition n := 3.
End ModuleInstance.
Module ModuleInstanceUtils := SigUtils ModuleInstance.
它并不是特别难,但有一个很大的局限性:您不能将任何实用程序用作签名的一部分(例如,使类型签名更短)。另一个限制是您的基本定义和派生定义/属性位于不同的模块中,因此如果您符合参考资格,则必须使用正确的名称。但是,如果您导入模块,则无关紧要。
这是标准库在一些地方遵循的模式;例如,FSetFacts
和FSetProperties
仿函数。
答案 1 :(得分:0)
作为https://stackoverflow.com/a/49322214/53974的替代方法,有时可以使用Include
,它支持非常有限的递归链接特殊情况。
就像在该答案中一样,您应该将定义放在模块函子中,但随后可以Include
在签名的其余部分和实现模块中使用。这样可以重用您的定义以缩短声明,并将它们作为同一模块的一部分。
Require Import Omega.
Module Type Sig.
Parameter n : nat.
End Sig.
(* this is the module functor *)
Module SigUtils (S:Sig).
Definition n_plus_1 := S.n + 1.
End SigUtils.
Module ModuleInstance <: Sig.
Definition n := 3.
Include SigUtils.
End ModuleInstance.
Print ModuleInstance.
Module Type Sig2 <: Sig.
Include Sig.
Include SigUtils.
Parameter n_plus_1_eq: n_plus_1 = 1 + n.
End Sig2.
Module ModuleInstance2 <: Sig2.
Include ModuleInstance.
Lemma n_plus_1_eq: n_plus_1 = 1 + n.
Proof. unfold n_plus_1. omega. Qed.
Lemma n_plus_1_neq: n_plus_1 <> 2 + n.
Proof. unfold n_plus_1. omega. Qed.
End ModuleInstance2.
Print ModuleInstance2.
但是,您需要提防Include
的语义(例如,参见
https://stackoverflow.com/a/49717951/53974)。特别是,如果您将一个模块包含在两个不同的模块中,则会得到不同的定义。上面,SigUtils
一次包含在Module Type
中,一次包含在实现的Module
中,这是允许的。