我发现我经常在编写这样的代码:
Fixpoint get_fresh w (Γ : Ctx) : Pat w * Ctx:=
match w with
...
| w1 ⊗ w2 => let (p1, Γ1) := get_fresh w1 Γ in
match Γ ⋓ Γ1 with
| None => (dummy_pat _, dummy_ctx)
| Some Γ' => (p1,Γ')
end.
将永远不会输入None
分支。 (在这里,不可能进入分支,有时我们永远不会在适当的输入上进入分支。)
实现不应返回的虚拟值的最佳方法是什么?
一种简单的方法是简单地声明
Parameter dummy_pat : forall W, Pat W.
Parameter dummy_ctx : Ctx.
但这听起来似乎是一种不好的做法-因为所有用户都知道Ctx
和Pat W
可能没有居民。 (对于诸如Pat W
之类的相关类型尤其如此。)
我可以为dummy_pat
和dummy_ctx
给出简单的定义,但是我不希望用户对此分支进行推理。我可以将dummy_pat
和dummy_ctx
声明为不透明,但是不透明性很容易反转。
最后,我想我可以将它们声明为sigma类型的投影,但这似乎会造成混淆,并且我不确定它是否解决了这种情况的推理问题。
(请注意,我不想本质上证明使用Program
或其他方式无法访问这些分支。我发现这些函数很难编写和使用。)
有什么建议吗?
答案 0 :(得分:1)
以下声明模块的方法可能具有更好的不透明度保证(但是如果我错了,我将非常有兴趣知道!):
Module Type DummySig.
Parameter dummy_pat : forall W, Pat W.
Parameter dummy_ctx : Ctx.
End DummySig.
Module Import Dummy : DummySig.
Definition dummy_pat := (* some simple definition *)
Definition dummy_ctx := (* some simple definition *)
End Dummy.
Module Import Dummy : DummySig.
是Module Dummy : DummySig
的缩写,后跟Import Dummy.
命令后的End Dummy.
。
Module Dummy : DummySig.
声明一个模块类型为(或 signature )DummySig
的模块,并密封该模块,以便仅在DummySig
关于此Dummy
模块是可见的。
这是一个强大的抽象边界,它隐藏了所有实现细节。特别是,Parameter
中的DummySig
使定义在Dummy
中不透明,并且Dummy
中定义但未出现在DummySig
中的标识符根本不可见从模块外部。
据我所知,这种不透明是不可逆的,这是这里的重点。
为了进行比较,声明模块的其他两种方法是:
Module M.
公开了模块M
中的所有内容,因此它主要是一种命名空间。
Module M <: MSig.
,还公开了M
中的所有内容,同时检查它是否实现了签名MSig
(通过Module Type MSig.
定义),而没有“密封”方面的Module M : Sig.
。
您还可以通过模块函子将虚拟变量转换为实际参数...
Module MyProject (Dummy : DummySig).
Import Dummy.
...
或部分;为避免必须传递虚拟变量,类型类可能会有用。
Class Dummy (A : Type) := { dummy : A }.
Section Dummies.
Context `{forall W, Dummy (Pat W)}.
Context `{Dummy Ctx}.
...
最终,我想知道用户能否推理出无法访问的分支是否真的很糟糕。