Agda的静态平衡树木

时间:2015-06-09 21:12:46

标签: tree agda dependent-type

我通过学习Agda来教授自己的依赖类型。

这是一个二进制树的类型,它们的大小是平衡的。

open import Data.Nat
open import Data.Nat.Properties.Simple

data T (A : Set) : ℕ -> Set where
  empty : T A 0
  leaf : A -> T A 1
  bal : ∀ {n} -> T A n -> T A n -> T A (n + n)
  heavyL : ∀ {n} -> T A (suc n) -> T A n -> T A (suc (n + n))

树可以完全平衡(bal),或者左子树可以包含比右子树(heavyL)多一个元素。 (在这种情况下,下一个插入将进入正确的子树。)这个想法是插入将在树的左半部分和右半部分之间翻转,有效地(确定地)改变输入列表。

我无法定义insert类型检查:

insert : ∀ {A n} -> A -> T A n -> T A (suc n)
insert x empty = leaf x
insert x (leaf y) = bal (leaf x) (leaf y)
insert x (bal l r) = heavyL (insert x l) r
insert x (heavyL l r) = bal l (insert x r)

Agda拒绝bal l (insert x r)作为heavyL案件的右侧:

.n + suc .n != suc (.n + .n) of type ℕ
when checking that the expression bal l (insert x r) has type
T .A (suc (suc (.n + .n)))

我试图用证明修补我的定义......

insert x (heavyL {n} l r) rewrite +-suc n n = bal l (insert x r)

...但我得到了同样的错误消息。 (我误解了rewrite的作用吗?)

我也尝试在相同的证明假设下转换相同大小的树:

convertT : ∀ {n m A} -> T A (n + suc m) -> T A (suc (n + m))
convertT {n} {m} t rewrite +-suc n m = t

insert x (heavyL {n} l r) rewrite +-suc n n = bal (convertT l) (convertT (insert x r))

Agda接受这种可能性,但以黄色突出显示等式。我想我需要明确给出我传递给bal构造函数的两个子树的大小:

insert x (heavyL {n} l r) rewrite +-suc n n = bal {n = suc n} (convertT l) (convertT (insert x r))

但现在我再次收到相同的错误消息!

n + suc n != suc (n + n) of type ℕ
when checking that the expression
bal {n = suc n} (convertT l) (convertT (insert x r)) has type
T .A (suc (suc (n + n)))

我没有想法。我确定我犯了一个愚蠢的错误。我究竟做错了什么?我需要做些什么来定义insert类型检查?

2 个答案:

答案 0 :(得分:4)

你的rewrite尝试几乎可行,但它所使用的平等方向是错误的。为了让它在正确的方向上工作,你可以翻转它:

open import Relation.Binary.PropositionalEquality
-- ...
insert x (heavyL {n} l r) rewrite sym (+-suc n n) = bal l (insert x r)

或使用with子句:

insert x (heavyL {n} l r) with bal l (insert x r)
... | t rewrite +-suc n n = t

另一种可能性是在右侧自己进行替换:

open import Relation.Binary.PropositionalEquality
-- ...
insert x (heavyL {n} l r) = subst (T _) (+-suc (suc n) n) (bal l (insert x r))

答案 1 :(得分:4)

你只需要在另一个方向上重写:

open import Relation.Binary.PropositionalEquality

insert : ∀ {A n} -> A -> T A n -> T A (suc n)
insert x empty = leaf x
insert x (leaf y) = bal (leaf y) (leaf y)
insert x (bal l r) = heavyL (insert x l) r
insert x (heavyL {n} l r) rewrite sym (+-suc n n) = bal l (insert x r)

您可以使用Agda的大孔机械来弄清楚发生了什么:

insert x (heavyL {n} l r) = {!!}
在类型检查并将光标放在{!!}之后

,您可以输入C-c C-,并获取

Goal: T .A (suc (suc (n + n)))
————————————————————————————————————————————————————————————
r  : T .A n
l  : T .A (suc n)
n  : ℕ
x  : .A
.A : Set

bal l (insert x r)放入洞中并输入C-c C-.后,您将获得

Goal: T .A (suc (suc (n + n)))
Have: T .A (suc (n + suc n))
————————————————————————————————————————————————————————————
r  : T .A n
l  : T .A (suc n)
n  : ℕ
x  : .A
.A : Set

所以存在不匹配。 rewrite修正了它:

insert x (heavyL {n} l r) rewrite sym (+-suc n n) = {!bal l (insert x r)!}

现在输入C-c C-.(在类型检查之后)给出

Goal: T .A (suc (n + suc n))
Have: T .A (suc (n + suc n))
————————————————————————————————————————————————————————————
r  : T .A n
l  : T .A (suc n)
x  : .A
.A : Set
n  : ℕ

您可以在洞中输入C-c C-r来完成定义。

  

Agda接受这种可能性,但强调了这个等式   黄色。

Agda无法推断n中的mn + suc m,因为n上存在模式匹配。在Agda邮件列表上有一个thread隐式参数。