Agda 和二叉搜索树

use*_*402 5 agda

请注意,这是一个作业,所以最好不要发布完整的解决方案,相反,我只是被卡住了,需要一些关于我接下来应该看什么的提示。

module BST where

open import Data.Nat
open import Relation.Binary.PropositionalEquality
open import Relation.Binary
open DecTotalOrder decTotalOrder using () renaming (refl to ?-refl; trans to ?-trans)


data Ord (n m : ?) : Set where
  smaller : n < m -> Ord n m
  equal   : n ? m -> Ord n m
  greater : n > m -> Ord n m

cmp : (n m : ?) -> Ord n m
cmp zero zero       = equal refl
cmp zero (suc n)    = smaller (s?s z?n)
cmp (suc n) zero    = greater (s?s z?n)
cmp (suc n) (suc m) with cmp n m 
... | smaller n<m-pf = smaller (s?s n<m-pf)
... | equal   n?m-pf = equal (cong suc n?m-pf)
... | greater n>m-pf = greater (s?s n>m-pf)


-- To keep it simple and to exclude duplicates,
-- the BST can only store [1..]
--
data BST (min max : ?) : Set where
  branch : (v : ?)
         ? BST min v ? BST v max 
         ? BST min max
  leaf   : min < max -> BST min max
Run Code Online (Sandbox Code Playgroud)

这些已经导入:

?-refl : ? {a} ? a ? a 

?-trans : ? {a b c} ? a ? b ? b ? c ? a ? c 
Run Code Online (Sandbox Code Playgroud)

我们需要实现这个扩展 BST 边界的函数:

widen : ?{min max newMin newMax}
      ? BST min max
      ? newMin ? min
      ? max ? newMax
      ? BST newMin newMax
Run Code Online (Sandbox Code Playgroud)

到目前为止我有这个:

widen : ?{min max newMin newMax}
      ? BST min max
      ? newMin ? min
      ? max ? newMax
      ? BST newMin newMax
widen (leaf min<max-pf) newMin<min-pf max<newMax-pf = BST newMin<min-pf max<newMax-pf
widen (branch v l r) newMin<min-pf max<newMax = branch v 
                                                (widen l newMin<min-pf max<newMax) 
                                                (widen r newMin<min-pf max<newMax)
Run Code Online (Sandbox Code Playgroud)

现在这显然不起作用,因为新边界不必严格小于/大于最小值/最大值。给出了一个提示:It is not strictly necessary, but you may find it helpful to implement an auxiliary function that widens the range of a strictly smaller than relation of the form min < max.这就是我在这里所做的,显然我需要改变一些东西,但我认为基本的想法就在那里。

这就是我所处的位置,我真的不知道从哪里开始,我已经做了尽可能多的研究,但是没有很多关于使用 Agda 的阅读材料。我可能需要使用 ?-refl 或 ?-trans 吗?

Vit*_*tus 5

这里棘手的部分是了解widen函数实际需要更改的内容。一旦你明白了,编写代码就相当容易了。

让我们从leaf部分开始,我们有:

widen (leaf min<max) newMin?min max?newMax = {! !}
Run Code Online (Sandbox Code Playgroud)

leaf min<max有类型BST min max。应用后widen,我们希望树具有类型BST newMin newMax- 这意味着我们必须将证明更改min < maxnewMin < newMax

幸运的是,我们知道newMin ? min并且max ? newMax. ?是可传递的(它遵循事实,它?形成了一个全序?)并且很容易遵循这一点newMin ? newMax- 这很好,但我们必须告诉 Agda。

这就是?-trans发挥作用的地方。回想起那个:

?-trans : ? {a b c} ? a ? b ? b ? c ? a ? c
Run Code Online (Sandbox Code Playgroud)

这就是传递性的定义!正是我们正在寻找的。(相当小的)问题是我们的证明<与 一起使用?。如果他们没有

trans-4 : ? {a b c d} ? a ? b ? b ? c ? c ? d ? a ? d
Run Code Online (Sandbox Code Playgroud)

写起来相当容易(你只需要申请?-trans两次)。您可能想要实际编写此函数,它将帮助您完成下一部分。

我们知道a ? b( newMin ? min) 和c ? d( max ? newMax),但我们只知道b < c——我们不能只申请?-trans两次。看Data.Nat,我们发现

_<_ : Rel ? Level.zero
m < n = suc m ? n
Run Code Online (Sandbox Code Playgroud)

所以我们真正想写的是:

trans-4 : ? {a b c d} ? a ? b ? suc b ? c ? c ? d ? suc a ? d
Run Code Online (Sandbox Code Playgroud)

这有点难,所以让我们把它分成两步。我们需要证明:

trans? : ? {a b c} ? a ? b ? suc b ? c ? suc a ? c -- a ? b ? b < c ? a < c
trans? : ? {a b c} ? suc a ? b ? b ? c ? suc a ? c -- a < b ? b ? c ? a < c
Run Code Online (Sandbox Code Playgroud)

我们可以使用?-transif 我们有suc a ? suc b而不仅仅是a ? b. 但我们可以得到!如果a ? b,那么肯定a + 1 ? b + 1。再次快速查看标准库:

data _?_ : Rel ? Level.zero where
  z?n : ? {n}                 ? zero  ? n
  s?s : ? {m n} (m?n : m ? n) ? suc m ? suc n
Run Code Online (Sandbox Code Playgroud)

我把剩下的留作练习。一旦你知道了newMin < newMax,重构 中的证明leaf就变得微不足道了。


branch部分实际上用 Agda 编写要容易得多,当然,棘手的部分是弄清楚我们需要更改哪些证明。

我们有:

widen (branch v l r) newMin?min max?newMax = {! !}
Run Code Online (Sandbox Code Playgroud)

同样,branch v l r有类型BST min max,我们想要BST newMin newMax. 正如您所注意到的,我们需要创建一个新分支并递归地加宽lr

如果我们想递归地应用widen,我们最好检查一下land的类型r

l : BST min v
r : BST v max
Run Code Online (Sandbox Code Playgroud)

因为这个答案已经很长了,我将讨论l子树,另一种情况是对称的。

问题是,当然,如果我们申请widenl,我们还需要提供两个新的证据。min没有改变,所以我们可以newMin?min作为第一个通过。第二个呢?我们不能再给它了max?newMax,因为我们的子树BST min v不是BST min max

我们最终的树必须看起来像BST newMin newMax,我们知道它必须包含v. 这为我们提供了一种扩展左子树类型的选择 - BST newMin v

这意味着什么?因此,第二个证明的类型v ? v很容易从这里开始!

快乐编码!