我想以某种方式限制允许构造函数在归纳定义中采用哪种输入。假设我想说如下定义二进制数:
Inductive bin : Type :=
| O : bin
| D : bin -> bin
| S : bin -> bin.
这里的想法是D通过在末尾添加零来使非零数字加倍,并且S将数字作为最后一位数加零,并将最后一位数字变为1。这意味着以下是合法的数字:
S 0
D (S 0)
D (D (S 0))
虽然以下不是:
S (S 0)
D 0
有没有办法以干净的方式在归纳定义中强制执行此类限制?
答案 0 :(得分:7)
您可以定义bin
对谓词合法的含义,然后为遵守该谓词的bin
子集指定名称。然后,您使用Program Definition
和Program Fixpoint
而不是Definition
和Fixpoint
编写函数。对于递归函数,您还需要一个度量来证明函数的参数减小,因为函数不再是结构递归的。
Require Import Coq.Program.Program.
Fixpoint Legal (b1 : bin) : Prop :=
match b1 with
| O => True
| D O => False
| D b2 => Legal b2
| S (S _) => False
| S b2 => Legal b2
end.
Definition lbin : Type := {b1 : bin | Legal b1}.
Fixpoint to_un (b1 : bin) : nat :=
match b1 with
| O => 0
| D b2 => to_un b2 + to_un b2
| S b2 => Coq.Init.Datatypes.S (to_un b2)
end.
Program Definition zer (b1 : lbin) := O.
Program Fixpoint succ (b1 : lbin) {measure (to_un b1)} : lbin :=
但是this简单类型的方法可能会更容易。
答案 1 :(得分:1)
这可以通过归纳递归定义来完成 - 但遗憾的是Coq不支持这些定义。
从面向对象的编程角度来看,O
,D
和S
是bin
的子类型,然后可以定义它们的构造函数类型,而无需求助于逻辑谓词,但Coq本身也不支持面向对象的编程。
然而,Coq确实有类型类。所以我可能做的是使bin
成为类型类,并使每个构造函数成为一个单独的归纳类型,每个类型都有一个bin
类型类的实例。我不确定类型类的方法是什么。