Agda文档提供了一些如何使用Data.AVL
模块的示例:
http://darcsden.com/abel/AgdaPrelude/browse/README/AVL.agda
在示例中,模块在导入时实例化一次,参数指定存储在树中的值的类型,以及键类型的顺序。
如何在同一个客户端模块中使用不同值类型的AVL树(例如字符串树和数字树)?
答案 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 ℕ}))
你被警告过了。 :)