这是一个简单的理论,写在简单的HOL上:
theory ToyList
imports Main
begin
no_notation Nil ("[]") and Cons (infixr "#" 65) and append (infixr "@" 65)
hide_type list
hide_const rev
datatype 'a list = Nil ("[]") | Cons 'a "'a list" (infixr "#" 65)
primrec snoc :: "'a list => 'a => 'a list" (infixr "#>" 65)
where
"[] #> y = y # []" |
"(x # xs) #> y = x # (xs #> y)"
primrec rev :: "'a list => 'a list"
where
"rev [] = []" |
"rev (x # xs) = (rev xs) #> x"
lemma rev_snoc [simp]: "rev(xs #> y) = y # (rev xs)"
apply(induct_tac xs)
apply(auto)
done
theorem rev_rev [simp]: "rev(rev xs) = xs"
apply(induct_tac xs)
apply(auto)
done
end
snoc
与cons
相反。它会在列表末尾添加一个项目。
我想通过HOLCF证明一个类似的引理。在第一阶段,我只考虑严格的清单。我在HOLCF中声明了严格列表的域名。我还声明了两个递归函数:
ssnoc
- 将项目附加到列表的末尾srev
- 撤消列表前缀s
表示“严格”。
theory Test
imports HOLCF
begin
domain 'a SList = SNil | SCons "'a" "'a SList"
fixrec ssnoc :: "'a SList → 'a → 'a SList"
where
"ssnoc ⋅ SNil ⋅ x = SCons ⋅ x ⋅ SNil" |
"ssnoc ⋅ ⊥ ⋅ x = ⊥" |
"x ≠ ⊥ ∧ xs ≠ ⊥ ⟹ ssnoc ⋅ (SCons ⋅ x ⋅ xs) ⋅ y = SCons ⋅ x ⋅ (ssnoc ⋅ xs ⋅ y)"
fixrec srev :: "'a SList → 'a SList"
where
"srev ⋅ ⊥ = ⊥" |
"srev ⋅ SNil = SNil" |
"x ≠ ⊥ ∧ xs ≠ ⊥ ⟹ srev ⋅ (SCons ⋅ x ⋅ xs) = ssnoc ⋅ (srev ⋅ xs) ⋅ x"
lemma srev_singleton [simp]:
"srev ⋅ (SCons ⋅ a ⋅ SNil) = SCons ⋅ a ⋅ SNil"
apply(induct)
apply(simp_all)
done
lemma srev_ssnoc [simp]:
"srev ⋅ (ssnoc ⋅ xs ⋅ a) = SCons ⋅ a ⋅ (srev ⋅ xs)"
apply(induct xs)
apply(simp_all)
done
lemma srev_srev [simp]:
"srev ⋅ (srev ⋅ xs) = xs"
apply(induct xs)
apply(simp_all)
done
end
我试图证明列表的双重回复等于原始列表(srev_srev
引理)。我已经宣布了两个辅助引理:
srev_singleton
- 单例列表的反向是原始单例列表srev_ssnoc
- 列表的还原等于从原始列表的最后一项开始的列表,附加原始列表的其余项目的还原但我无法证明任何一个引理。你能指出错误吗?
为什么在函数定义中需要前置条件"x ≠ ⊥ ∧ xs ≠ ⊥"
?为什么我要明确声明"srev ⋅ ⊥ = ⊥"
和"ssnoc ⋅ ⊥ ⋅ x = ⊥"
。我想在HOLCF中,如果任何参数未定义,默认情况下函数是未定义的。
答案 0 :(得分:2)
如果你的目的是建模列表la Haskell(又名"懒惰列表"),那么你应该使用类似的东西:
PHPUnit 3.7.21 by Sebastian Bergmann.
(注意"懒惰" domain 'a list = Nil ("[]") | Cons (lazy 'a) (lazy "'a list") (infix ":" 65)
的注释)。那么你不需要对你的第三个等式做出假设。如,
Cons
您所谓的fixrec append :: "'a list → 'a list → 'a list"
where
"append $ [] $ ys = ys"
| "append $ (x : xs) $ ys = x : (append $ xs $ ys)"
和
ssnoc
反向。
然而,由于这种类型的列表允许"无限"价值观,你将无法证明fixrec reverse :: "'a list → 'a list"
where
"reverse $ [] = []"
| "reverse $ (x : xs) = append $ xs $ (x : [])"
一般(因为它没有)。这仅适用于有限列表,可以归纳为特征。 (例如,请参阅https://arxiv.org/abs/1306.1340以获得更详细的讨论。)
但是,如果您不想为懒惰列表建模(即,实际上并不想要数据类型中的" lazy"注释),那么在没有假设的情况下,您的方程式可能无法实现。现在,如果方程具有这些假设,则它们仅适用于满足假设的情况。所以获得,你将无法证明reverse $ (reverse $ xs) = xs
(没有额外的假设)。可能再次有可能通过归纳谓词获得适当的假设,但我没有进一步调查。
更新:在HOLCF中使用严格列表后,我还有更多评论:
首先,我的猜测是,由于内部构造,fixrec规范中的前提条件是必要的,但我们之后可以将它们除掉。
我设法证明你的引理如下。为了完整起见,我给出了理论文件的全部内容。首先要确保符号与现有符号没有冲突:
reverse $ (reverse $ xs) = xs
然后定义严格列表的类型
no_notation
List.Nil ("[]") and
Set.member ("op :") and
Set.member ("(_/ : _)" [51, 51] 50)
和函数domain 'a list = Nil ("[]") | Cons 'a "'a list" (infixr ":" 65)
。
snoc
现在,我们通过以下方式获得第二个等式的无条件变体:
fixrec snoc :: "'a list → 'a → 'a list"
where
"snoc $ [] $ y = y : []"
| "x ≠ ⊥ ⟹ xs ≠ ⊥ ⟹ snoc $ (x:xs) $ y = x : snoc $ xs $ y"
是严格的(请注意snoc
的用法)。fixrec_simp
是严格的(此处需要归纳)。的
snoc
然后是函数lemma snoc_bot1 [simp]: "snoc $ ⊥ $ y = ⊥" by fixrec_simp
lemma snoc_bot2 [simp]: "snoc $ xs $ ⊥ = ⊥" by (induct xs) simp_all
lemma snoc_Cons [simp]: "snoc $ (x:xs) $ y = x : snoc $ xs $ y"
by (cases "x = ⊥"; cases "xs = ⊥"; cases "y = ⊥";simp)
reverse
又是第二个等式的无条件变体:
fixrec reverse :: "'a list → 'a list"
where
"reverse $ [] = []"
| "x ≠ ⊥ ⟹ xs ≠ ⊥ ⟹ reverse $ (x : xs) = snoc $ (reverse $ xs) $ x"
现在关于lemma reverse_bot [simp]: "reverse $ ⊥ = ⊥" by fixrec_simp
lemma reverse_Cons [simp]: "reverse $ (x : xs) = snoc $ (reverse $ xs) $ x"
by (cases "x = ⊥"; cases "xs = ⊥"; simp)
和reverse
的引理你也有:
snoc
最后是理想的引理:
lemma reverse_snoc [simp]: "reverse $ (snoc $ xs $ y) = y : reverse $ xs"
by (induct xs) simp_all
我获得此解决方案的方法只是查看失败尝试的剩余子目标,然后获得更多失败的尝试,查看剩余的子目标,重复,...