如何在Agda中编写arity-generic函数?是否可以编写完全依赖和Universe多态的arity-generic函数?
答案 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 Y
,N-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
的元素X
。 Xs
以前的类型为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。