Agda中的Arity-generic编程

时间:2015-03-21 05:14:34

标签: generic-programming agda dependent-type arity

如何在Agda中编写arity-generic函数?是否可以编写完全依赖和Universe多态的arity-generic函数?

1 个答案:

答案 0 :(得分:6)

我将以n-ary合成函数为例。

最简单的版本

open import Data.Vec.N-ary

comp : ∀ n {α β γ} {X : Set α} {Y : Set β} {Z : Set γ}
     -> (Y -> Z) -> N-ary n X Y -> N-ary n X Z
comp  0      g y = {!!}
comp (suc n) g f = {!!}

以下是N-ary模块中Data.Vec.N-ary的定义方式:

N-ary : ∀ {ℓ₁ ℓ₂} (n : ℕ) → Set ℓ₁ → Set ℓ₂ → Set (N-ary-level ℓ₁ ℓ₂ n)
N-ary zero    A B = B
N-ary (suc n) A B = A → N-ary n A B

即。 comp会收到一个n,一个函数g : Y -> Z和一个f函数,其中包含n和结果类型Y。< / p>

comp 0 g y = {!!}案例中,我们有

Goal : Z
y    : Y
g    : Y -> Z

因此可以通过g y轻松填充孔。

comp (suc n) g f = {!!}案例中,N-ary (suc n) X Y缩减为X -> N-ary n X YN-ary (suc n) X Z缩减为X -> N-ary n X Z。所以我们有

Goal : X -> N-ary n X Z
f    : X -> N-ary n X Y
g    : Y -> Z

C-c C-r将洞缩小为λ x -> {!!},现在Goal : N-ary n X Z,可以填comp n g (f x)。所以整个定义是

comp : ∀ n {α β γ} {X : Set α} {Y : Set β} {Z : Set γ}
     -> (Y -> Z) -> N-ary n X Y -> N-ary n X Z
comp  0      g y = g y
comp (suc n) g f = λ x -> comp n g (f x)

即。 comp收到类型为n的{​​{1}}个参数,对其应用X,然后将f应用于结果。

具有从属g

的最简单版本

g的类型为g

(y : Y) -> Z y

洞里应该有什么?我们不能像以前一样使用comp : ∀ n {α β γ} {X : Set α} {Y : Set β} {Z : Y -> Set γ} -> ((y : Y) -> Z y) -> (f : N-ary n X Y) -> {!!} comp 0 g y = g y comp (suc n) g f = λ x -> comp n g (f x) ,因为N-ary n X Z现在是一个函数。如果Z是函数,我们需要将其应用于类型为Z的内容。但是,获取Y类型的唯一方法是将Y应用于f类型的n个参数。这就像我们的X,但仅限于类型级别:

comp

然后Comp : ∀ n {α β γ} {X : Set α} {Y : Set β} -> (Y -> Set γ) -> N-ary n X Y -> Set (N-ary-level α γ n) Comp 0 Z y = Z y Comp (suc n) Z f = ∀ x -> Comp n Z (f x)

comp

具有不同类型

的参数的版本

有&#34; Arity-generic datatype-generic programming&#34;本文,其中介绍了如何编写arity-generic函数,这些函数接收不同类型的参数。我们的想法是将类型向量作为参数传递,并以comp : ∀ n {α β γ} {X : Set α} {Y : Set β} {Z : Y -> Set γ} -> ((y : Y) -> Z y) -> (f : N-ary n X Y) -> Comp n Z f comp 0 g y = g y comp (suc n) g f = λ x -> comp n g (f x) 的风格折叠它:

N-ary

然而,即使我们提供其长度,Agda也无法推断出该向量。因此,本文还提供了一个currying操作符,它通过一个函数显式地接收一个类型向量,一个函数,它接收arrTy : {n : N} → Vec Set (suc n) → Set arrTy {0} (A :: []) = A arrTy {suc n} (A :: As) = A → arrTy As 隐式参数。

这种方法有效,但它不能扩展到完全宇宙多态函数。我们可以通过用n运算符替换Vec数据类型来避免所有这些问题:

_^_

_^_ : ∀ {α} -> Set α -> ℕ -> Set α A ^ 0 = Lift ⊤ A ^ suc n = A × A ^ n A ^ n同构。然后我们的新Vec A n

N-ary

为简单起见,所有类型都位于_->ⁿ_ : ∀ {n} -> Set ^ n -> Set -> Set _->ⁿ_ {0} _ B = B _->ⁿ_ {suc _} (A , R) B = A -> R ->ⁿ B Set现在是

comp

带有从属comp : ∀ n {Xs : Set ^ n} {Y Z : Set} -> (Y -> Z) -> (Xs ->ⁿ Y) -> Xs ->ⁿ Z comp 0 g y = g y comp (suc n) g f = λ x -> comp n g (f x) 的版本:

g

完全依赖和宇宙多态Comp : ∀ n {Xs : Set ^ n} {Y : Set} -> (Y -> Set) -> (Xs ->ⁿ Y) -> Set Comp 0 Z y = Z y Comp (suc n) Z f = ∀ x -> Comp n Z (f x) comp : ∀ n {Xs : Set ^ n} {Y : Set} {Z : Y -> Set} -> ((y : Y) -> Z y) -> (f : Xs ->ⁿ Y) -> Comp n Z f comp 0 g y = g y comp (suc n) g f = λ x -> comp n g (f x)

关键思想是将类型向量表示为嵌套依赖对:

comp

第二种情况类似于&#34;类型Sets : ∀ {n} -> (αs : Level ^ n) -> ∀ β -> Set (mono-^ (map lsuc) αs ⊔ⁿ lsuc β) Sets {0} _ β = Set β Sets {suc _} (α , αs) β = Σ (Set α) λ X -> X -> Sets αs β 使得所有其他类型依赖于X&#34;的元素。我们的新X很简单:

N-ary

一个例子:

Fold : ∀ {n} {αs : Level ^ n} {β} -> Sets αs β -> Set (αs ⊔ⁿ β)
Fold {0}      Y      = Y
Fold {suc _} (X , F) = (x : X) -> Fold (F x)

但现在postulate explicit-replicate : (A : Set) -> (n : ℕ) -> A -> Vec A n test : Fold (Set , λ A -> ℕ , λ n -> A , λ _ -> Vec A n) test = explicit-replicate Z的类型是什么?

g

回想一下,comp : ∀ n {β γ} {αs : Level ^ n} {Xs : Sets αs β} {Z : {!!}} -> {!!} -> (f : Fold Xs) -> Comp n Z f comp 0 g y = g y comp (suc n) g f = λ x -> comp n g (f x) 以前的类型为f,但Xs ->ⁿ Y现在隐藏在这些嵌套的从属对的末尾,并且可以依赖于来自任何Y的元素XXs以前的类型为Z,因此现在我们需要将Y -> Set γ追加到Set γ,使所有Xs隐含:

x

好的,_⋯>ⁿ_ : ∀ {n} {αs : Level ^ n} {β γ} -> Sets αs β -> Set γ -> Set (αs ⊔ⁿ β ⊔ γ) _⋯>ⁿ_ {0} Y Z = Y -> Z _⋯>ⁿ_ {suc _} (_ , F) Z = ∀ {x} -> F x ⋯>ⁿ Z ,哪种类型有Z : Xs ⋯>ⁿ Set γ?以前是g。我们需要再次向嵌套的依赖对添加一些东西,因为(y : Y) -> Z y再次被隐藏,现在只能以依赖的方式隐藏:

Y

最后

Πⁿ : ∀ {n} {αs : Level ^ n} {β γ}
   -> (Xs : Sets αs β) -> (Xs ⋯>ⁿ Set γ) -> Set (αs ⊔ⁿ β ⊔ γ)
Πⁿ {0}      Y      Z = (y : Y) -> Z y
Πⁿ {suc _} (_ , F) Z = ∀ {x} -> Πⁿ (F x) Z

测试:

Comp : ∀ n {αs : Level ^ n} {β γ} {Xs : Sets αs β}
     -> (Xs ⋯>ⁿ Set γ) -> Fold Xs -> Set (αs ⊔ⁿ γ)
Comp  0      Z y = Z y
Comp (suc n) Z f = ∀ x -> Comp n Z (f x)

comp : ∀ n {β γ} {αs : Level ^ n} {Xs : Sets αs β} {Z : Xs ⋯>ⁿ Set γ}
     -> Πⁿ Xs Z -> (f : Fold Xs) -> Comp n Z f
comp  0      g y = g y
comp (suc n) g f = λ x -> comp n g (f x)

请注意参数中的依赖关系以及length : ∀ {α} {A : Set α} {n} -> Vec A n -> ℕ length {n = n} _ = n explicit-replicate : (A : Set) -> (n : ℕ) -> A -> Vec A n explicit-replicate _ _ x = replicate x foo : (A : Set) -> ℕ -> A -> ℕ foo = comp 3 length explicit-replicate test : foo Bool 5 true ≡ 5 test = refl 的结果类型。此外,explicit-replicate位于Set,而Set₁位于A - 这说明了宇宙多态性。

说明

AFAIK,隐含论证没有可理解的理论,所以当第二个函数(即Set)收到隐式参数时,我不知道所有这些东西是如何工作的。这个测试:

f

至少通过了。

如果某个类型所在的Universe依赖于某个值,则

foo' : ∀ {α} {A : Set α} -> ℕ -> A -> ℕ foo' = comp 2 length (λ n -> replicate {n = n}) test' : foo' 5 true ≡ 5 test' = refl 无法处理函数。例如

comp

但这对于Agda来说很常见,例如:您无法将明确的explicit-replicate' : ∀ α -> (A : Set α) -> (n : ℕ) -> A -> Vec A n explicit-replicate' _ _ _ x = replicate x ... because this would result in an invalid use of Setω ... error : ∀ α -> (A : Set α) -> ℕ -> A -> ℕ error = comp 4 length explicit-replicate' 应用于自身:

id

code