直到几天前,我总是定义一个类型,然后直接证明了关于类型的定理。现在我尝试使用类型类。
问题
问题在于我无法为下面的cNAT
类型myD
实例化,而且它似乎是因为simp
对抽象函数没有影响cNAT
,我已使用primrec
函数cNAT_myD
制作了具体内容。由于instance proof
之后发生的自动化,我只能猜测发生了什么。
问题
Q1:下面,在instantiation myD :: (type) cNAT
语句中,您能告诉我如何完成证明,以及为什么我可以证明以下定理,但不能证明类型类证明,需要injective
?
theorem dNAT_1_to_1: "(dNAT n = dNAT m) ==> n = m"
assumes injective: "(cNAT n = cNAT m) ==> n = m"
Q2:这不是那么重要,但最底层是这句话:
instantiation myD :: (type) cNAT2
它涉及我试图实例化cNAT
的另一种方式。你能告诉我为什么我Failed to refine any pending goal
shows
了吗?我在源代码中添加了一些注释来解释我为设置它所做的一些事情。我使用了这个稍微修改过的公式来满足要求injective
:
assumes injective: "!!n m. (cNAT2 n = cNAT2 m) --> n = m"
我设计的datatype
就是这个,这对某些人来说可能对我有用:(更新:好吧,也许是另一个例子。一个好的心理练习是我试着弄清楚我怎么能够除了'a myD list
之外,[]
内有一些内容。使用BNF
,类似datatype_new 'a myD = myS "'a myD fset"
的内容会向我发出警告,指出右边有一个未使用的类型变量 - 手边)
datatype 'a myD = myL "'a myD list"
类型类是这样的,它需要从nat
到'a
的内射函数:
class cNAT =
fixes cNAT :: "nat => 'a"
assumes injective: "(cNAT n = cNAT m) ==> n = m"
fun get_myL :: "'a myD => 'a myD list" where
"get_myL (myL L) = L"
primrec dNAT :: "nat => 'a myD" where
"dNAT 0 = myL []"
|"dNAT (Suc n) = myL (myL [] # get_myL(dNAT n))"
fun myD2nat :: "'a myD => nat" where
"myD2nat (myL []) = 0"
|"myD2nat (myL (x # xs)) = Suc(myD2nat (myL xs))"
theorem left_inverse_1 [simp]:
"myD2nat(dNAT n) = n"
apply(induct n, auto)
by(metis get_myL.cases get_myL.simps)
theorem dNAT_1_to_1:
"(dNAT n = dNAT m) ==> n = m"
apply(induct n)
apply(simp) (*
The simp method expanded dNAT.*)
apply(metis left_inverse_1 myD2nat.simps(1))
by (metis left_inverse_1)
instantiation myD :: (type) cNAT
begin
primrec cNAT_myD :: "nat => 'a myD" where
"cNAT_myD 0 = myL []"
|"cNAT_myD (Suc n) = myL (myL [] # get_myL(cNAT_myD n))"
instance
proof
fix n m :: nat
show "cNAT n = cNAT m ==> n = m"
apply(induct n)
apply(simp) (*
The simp method won't expand cNAT to cNAT_myD's definition.*)
by(metis injective)+ (*
Metis proved it without unfolding cNAT_myD. It's useless. Goals always remain,
and the type variables in the output panel are all weird.*)
oops
end
show
(*I define a variation of `injective` in which the `assumes` definition, the
goal, and the `show` statement are exactly the same, and that strange `fails
to refine any pending goal shows up.*)
class cNAT2 =
fixes cNAT2 :: "nat => 'a"
assumes injective: "!!n m. (cNAT2 n = cNAT2 m) --> n = m"
instantiation myD :: (type) cNAT2
begin
primrec cNAT2_myD :: "nat => 'a myD" where
"cNAT2_myD 0 = myL []"
|"cNAT2_myD (Suc n) = myL (myL [] # get_myL(cNAT2_myD n))"
instance
proof (*
goal: !!n m. cNAT2 n = cNAT2 m --> n = m.*)
show
"!!n m. cNAT2 n = cNAT2 m --> n = m"
(*Failed to refine any pending goal
Local statement fails to refine any pending goal
Failed attempt to solve goal by exported rule:
cNAT2 (n::nat) = cNAT2 (m::nat) --> n = m *)
答案 0 :(得分:1)
您的函数cNAT
在其结果类型中是多态的,但类型变量不会出现在参数中。这通常会导致类型推断计算出比您想要的更通用的类型。对于cNAT
的情况,Isabelle推断出cNAT
语句中show
的两次出现nat => 'b
类'b
排序cNAT
},但他们在目标中的类型是nat => 'a myD
。你可以在jEdit中通过 Ctrl - 在cNAT
次出现时看到这个以检查类型。在ProofGeneral中,您可以使用using [[show_consts]]
启用类型打印。
因此,您必须在show
语句中明确约束类型,如下所示:
fix n m
assume "(cNAT n :: 'a myD) = cNAT m"
then show "n = m"
请注意,在!!
语句中使用Isabelle的元连词==>
和show
通常不是一个好主意,您最好使用fix
/ {对它们进行重新措辞{1}} / assume
。