我可以轻松获取密钥列表,如下所示:
open import Relation.Binary
open import Relation.Binary.PropositionalEquality using (_≡_)
module AVL-Tree-Functions
{ k v ℓ } { Key : Set k }
( Value : Key → Set v )
{ _<_ : Rel Key ℓ }
( isStrictTotalOrder : IsStrictTotalOrder _≡_ _<_ )
where
open import Data.AVL Value isStrictTotalOrder public
open import Data.List.Base
open import Function
open import Data.Product
keys : Tree → List Key
keys = Data.List.Base.map proj₁ ∘ toList
但我不清楚如何指定返回值列表的函数类型。这是我的第一次尝试:
-- this fails to typecheck
values : Tree → List Value
values = Data.List.Base.map proj₂ ∘ toList
相关地,我也对Data.AVL中Value
的声明感到困惑。使用( Value : Key → Set v )
,树中每个Value的类型看起来都取决于密钥?或类似的东西。然后我认为proj 2会返回Set v
类型的东西,所以我尝试了这个:
-- this also fails to typecheck
values : Tree → List (Set v)
values = Data.List.Base.map proj₂ ∘ toList
但这也不起作用(它失败并出现不同的错误)。请说明如何从Data.AVL.Tree获取值列表(或解释为什么它不可能)。奖金:解释为什么我的两次尝试都失败了。
P.S。这是使用Agda的版本2.4.2.3和agda-stdlib。
答案 0 :(得分:5)
看起来树中每个Value的类型都依赖于 键?
是。这就是为什么你的代码没有进行类型检查的原因 - List
s是同质的,但不同的Value
具有不同的索引(即依赖于不同的Key
s)因此不同类型。
您可以使用异类列表,如 gallais &#39;回答,但索引列表可能就足够了:
open import Level
data IList {ι α} {I : Set ι} (A : I -> Set α) : Set (ι ⊔ α) where
[]ᵢ : IList A
_∷ᵢ_ : ∀ {i} -> A i -> IList A -> IList A
projs₂ : ∀ {α β} {A : Set α} {B : A -> Set β} -> List (Σ A B) -> IList B
projs₂ [] = []ᵢ
projs₂ ((x , y) ∷ ps) = y ∷ᵢ projs₂ ps
或者你可以结合使用这些技术:
data IHList {ι α} {I : Set ι} (A : I -> Set α) : List I -> Set (ι ⊔ α) where
[]ᵢ : IHList A []
_∷ᵢ_ : ∀ {i is} -> A i -> IHList A is -> IHList A (i ∷ is)
projs₂ : ∀ {α β} {A : Set α} {B : A -> Set β}
-> (xs : List (Σ A B)) -> IHList B (Data.List.Base.map proj₁ xs)
projs₂ [] = []ᵢ
projs₂ ((x , y) ∷ ps) = y ∷ᵢ projs₂ ps
答案 1 :(得分:3)
Value : Key → Set v
的含义是值的类型可能取决于与之关联的键。这意味着AVL树可能包含布尔值,Nats等,只要它们存储的密钥反映了这一事实。有点像记录可以存储不同类型的值这一事实(类型由字段名称决定)。
现在,它们有不同的方法:你可以将整个树的内容提取到键/值对的列表中(因为列表的元素都是相同的,你需要在这里建立一对,以便一切具有相同的类型Σ Key Value
)。这就是toList
的作用。
另一种方法是使用通常称为HList
(H代表异构)的东西,它存储在类型级别的列表中每个元素的类型具有。我在这里通过对元素集的归纳来定义它是出于大小原因,但它根本不是至关重要的(如果你将它定义为数据类型,它会活得更高一层):
open import Level
open import Data.Unit
HList : {ℓ : Level} (XS : List (Set ℓ)) → Set ℓ
HList [] = Lift ⊤
HList (X ∷ XS) = X × HList XS
现在,您可以提供HList
值的类型。给定t
一个Tree
,它会使用您的keys
提取密钥列表,并通过在列表上映射Set
将其转换为Value
。
values : (t : Tree) → HList (List.map Value (keys t))
然后可以借助于toList
生成的列表中的辅助函数来提取值:
values t = go (toList t) where
go : (kvs : List (Σ Key Value)) → HList (List.map Value $ List.map proj₁ kvs)
go [] = lift tt
go (kv ∷ kvs) = proj₂ kv , go kvs