使用不同的元素类型实例化Data.AVL模块

时间:2013-12-26 16:27:29

标签: module standard-library agda

Agda文档提供了一些如何使用Data.AVL模块的示例:

http://darcsden.com/abel/AgdaPrelude/browse/README/AVL.agda

在示例中,模块在导入时实例化一次,参数指定存储在树中的值的类型,以及键类型的顺序。

如何在同一个客户端模块中使用不同值类型的AVL树(例如字符串树和数字树)?

1 个答案:

答案 0 :(得分:2)

您可以打开Data.AVL模块并直接使用这些功能。这非常不方便,因为无论何时使用此类功能,您都必须为其提供所有模块参数,这意味着您最终会得到如下代码:

open import Data.AVL
open import Data.Nat
open import Data.Nat.Properties
open import Data.String
  using (String)
open import Relation.Binary

test-tree : Tree (λ _ → String)
  (StrictTotalOrder.isStrictTotalOrder strictTotalOrder)
test-tree = empty (λ _ → String)
  (StrictTotalOrder.isStrictTotalOrder strictTotalOrder)

我们不要去那里。相反,我们将利用Agda可以创建和应用模块的事实(甚至在另一个模块中)。这是一个(完全是人为的,抱歉)的例子:

module M (A B : Set) where
  f : A → B → A
  f x _ = x

我们只需应用M

即可创建新模块
module M′ = M ℕ

如果我们询问M′.f的类型(例如,使用C-c C-d),我们会得到(B : Set) → ℕ → B → ℕ。如果您将其与M.f : (A : Set) (B : Set) → A → B → A进行比较,则可以看到确实替代A

另外,完全应用它:

module M″ = M ℕ String
-- or equivalently
module M″ = M′  String

我们得到了预期的M″.f : ℕ → String → ℕ


那么,我们如何将其应用于AVL?此时,您可能会看到接下来会发生什么:

module AVL[ℕ,String] = Data.AVL (λ _ → String)
  (StrictTotalOrder.isStrictTotalOrder strictTotalOrder)

module AVL[ℕ,ℕ] = Data.AVL (λ _ → ℕ)
  (StrictTotalOrder.isStrictTotalOrder strictTotalOrder)

来自AVL[ℕ,String]的所有内容都在树上运行,其中密钥为,值为String。以下是如何使用它:

tree₁ : AVL[ℕ,String].Tree
tree₁ = insert 42 "hello" empty
  where
  open AVL[ℕ,String]

tree₂ : AVL[ℕ,ℕ].Tree
tree₂ = insert 1 2 empty
  where
  open AVL[ℕ,ℕ]

请注意,我在本地打开AVL[ℕ,String]AVL[ℕ,ℕ]模块,以便我不必编写,例如AVL[ℕ,String].insert。没有中间模块,它看起来像:

tree₁ : _
tree₁ = insert 4 "hello" empty
  where
  open Data.AVL (λ _ → String)
    (StrictTotalOrder.isStrictTotalOrder strictTotalOrder)

这比直接使用这些功能还要好得多。


我们可以更进一步使用实例参数:

open import Data.Vec

module AVL-Instance
  {k} {Key : Set k}
  {v} {Value : Key → Set v}
  {ℓ} {_<_ : Rel Key ℓ}
  {{isStrictTotalOrder : IsStrictTotalOrder _≡_ _<_}}
  = Data.AVL Value isStrictTotalOrder

ℕ-IsStrictTotalOrder : _
ℕ-IsStrictTotalOrder =
  StrictTotalOrder.isStrictTotalOrder strictTotalOrder

open AVL-Instance
  hiding (Tree)

open module AVL-Type {k v} (Key : Set k) (Value : Key → Set v)
  = AVL-Instance {Key = Key} {Value = Value}
  using (Tree)

tree₁ : Tree ℕ λ _ → String
tree₁ = insert 4 "hello" empty

tree₂ : Tree ℕ (Vec ℕ)
tree₂ = insert 2 (0 ∷ 1 ∷ []) empty

这看起来效果很好,但我的感觉是,除了简单的例子之外,这将非常脆弱。

要解释我的直觉来自何处,请考虑:

open import Data.Vec
  hiding (lookup)
open import Data.Maybe

tree₃ : Maybe (Vec ℕ 2)
tree₃ = lookup 2 (insert 2 (0 ∷ 1 ∷ []) empty)

empty的类型是什么?它很可能是Tree ℕ (Vec ℕ)Tree ℕ λ _ → Vec ℕ 2或像Tree ℕ λ n → Vec ℕ (2 * n + 12)一样疯狂的东西。而不是猜测,Agda将拒绝这个定义并要求您填写更多信息:

tree₃ : Maybe (Vec ℕ 2)
tree₃ = lookup 2 (insert 2 (0 ∷ 1 ∷ []) (empty {Value = Vec ℕ}))

你被警告过了。 :)