我试图定义一个类型类的两个实例,其中一个将使用另一个实例。但是,除非我将函数的名称绑定到第二个定义之外,否则Coq无法确定它应该使用bexp中的类型类实例(请查看脏黑客的注释)。有没有办法避免在Coq中出现这种黑客行为?
Class Compilable ( A : Type ) := { compile : A -> bool }.
Inductive cexp : Type :=
| CAnd : cexp -> cexp -> cexp
| COr : cexp -> cexp -> cexp
| CProp : bexp -> cexp.
Instance: Compilable bexp :=
{ compile :=
fix compile b :=
match b with
(* elided *)
end
}.
Definition compile2 := compile.
Instance: Compilable cexp :=
{ compile :=
fix compile c :=
match c with
| CAnd x y => (compile x) && (compile y)
| COr x y => (compile x) || (compile y)
| CProp e => (compile2 e) (* <-- dirty hack *)
end
}.
答案 0 :(得分:3)
如果我们将compile
替换为其他名称(rec
),则可以修复此问题:
Instance: Compilable cexp :=
{ compile :=
fix rec c :=
match c with
| CAnd x y => (rec x) && (rec y)
| COr x y => (rec x) || (rec y)
| CProp e => (compile e)
end
}.
在this comment中,OP指出Haskell很容易处理这种情况。要理解Coq不这样做的原因,让我们来看看compile
的类型:
About compile.
compile : forall A : Type, Compilable A -> A -> bool
参数
A
,Compilable
是隐式和最大插入的
我们可以看到Coq更明确地说明类型类是如何工作的。当您调用compile e
Coq时插入占位符代表隐含参数,例如@compile _ _ e
(请参阅these slides,第21-25页以获取更多详细信息)。但是使用fix compile c
,您会隐藏前一个绑定,因此会出现类型错误。