我已经在Agda项目上工作了几个星期,尽可能地忽略了级别多态性。不幸的是(或者幸运的是)我似乎已经达到了我需要开始理解它的程度。
直到现在,我一直在使用级别变量时,只需要它们作为Rel
的第二个参数(或REL
的第三个参数)。否则我省略了它们,只是直接使用Set
。现在我有一些客户端代码明确量化了a
级别,并尝试将某些类型的Set a
形式传递给我现有的代码,现在代码不够多态。在下面的示例中,quibble
代表客户端代码,_[_]×[_]_
和≈-List
是我现有代码的典型代码,仅使用Set
。
module Temp where
open import Data.List
open import Data.Product
open import Level
open import Relation.Binary
-- Direct product of binary relations.
_[_]×[_]_ : {ℓ₁ ℓ₂ : Level} {A B C D : Set} → A × B → REL A C ℓ₁ → REL B D ℓ₂ → C × D → Set (ℓ₁ ⊔ ℓ₂)
(a , b) [ _R_ ]×[ _S_ ] (c , d) = a R c × b S d
-- Extend a setoid (A, ≈) to List A.
data ≈-List {ℓ : Level} {A : Set} (_≈_ : Rel A ℓ) : Rel (List A) ℓ where
[] : ≈-List _≈_ [] []
_∷_ : {x y : A} {xs ys : List A} → (x≈y : x ≈ y) → (xs≈ys : ≈-List _≈_ xs ys) → ≈-List _≈_ (x ∷ xs) (y ∷ ys)
quibble : {a ℓ : Level} {A : Set a} → Rel A ℓ → Rel (List (A × A)) ℓ
quibble _≈_ = ≈-List (λ x y → x [ _≈_ ]×[ _≈_ ] y)
在这里,我可以使用额外的级别参数≈-List
扩展a
的归纳定义,以便它可以采用类型为Set a
的类型参数,但后来我不清楚如何改变输入和输出关系的宇宙。然后问题蔓延到更复杂的定义,例如_[_]×[_]_
,我甚至不太清楚如何继续。
我应该如何概括给定示例中的签名,以便quibble
编译?我可以遵循一般规则吗?我看过this。
答案 0 :(得分:2)
我认为你不能将它推广到任意的Universe级别,并且仍然可以编译quibble
。二元关系的乘积可以非常容易地推广:你只需要为Set
到A
每种类型用一个字母装饰D
:
_[_]×[_]_ : ∀ {a b c d ℓ₁ ℓ₂}
{A : Set a} {B : Set b} {C : Set c} {D : Set d} →
A × B → REL A C ℓ₁ → REL B D ℓ₂ → C × D → Set (ℓ₁ ⊔ ℓ₂)
(a , b) [ _R_ ]×[ _S_ ] (c , d) = a R c × b S d
是的,遗憾的是,宇宙多态通常需要大量的样板代码。无论如何,推广≈-List
的唯一方法是允许Set a
A
。所以,你从:
data ≈-List {a ℓ} {A : Set a} (_≈_ : Rel A ℓ) : Rel (List A) a where
但问题在于:_∷_
构造函数的类型是什么? x
(和y
,xs
,ys
)的类型为A : Set a
,x≈y
的类型为x ≈ y : Rel A ℓ = A → A → Set ℓ
。这意味着构造函数的类型应为Set (max a ℓ)
,或标准库表示法Set (a ⊔ ℓ)
。
是的,如果我们将≈-List
概括为与A : Set a
一起使用,我们必须将其类型声明为Rel (List A) (a ⊔ ℓ)
。如果没有Rel (List A) ℓ
,x
,y
和xs
,您可以将其设为ys
- 但我认为这不是一种选择。这是死路一条:使用Set
s(因为zero ⊔ ℓ = ℓ
)或更改quibble
。
quibble
可能不会被挽救,但是当你处理宇宙多态时,让我给你一个很好的知识。有时您的类型为A : Set a
,类型为Set (a ⊔ b)
。现在,肯定是a ≤ a ⊔ b
,因此从Set a
转到Set (a ⊔ b)
不会导致任何矛盾(通常Set : Set
意义上的)。当然,标准库有一个工具。在Level
模块中,有一个名为Lift
的数据类型,让我们来看看它的定义:
record Lift {a ℓ} (A : Set a) : Set (a ⊔ ℓ) where
constructor lift
field lower : A
请注意,只有一个A
类型的字段(位于Set a
中),Lift A
本身的类型为Set (a ⊔ ℓ)
。因此,如果您有x : A : Set a
,则可以通过lift
:lift a : Lift A : Set (a ⊔ ℓ)
移至更高级别,反之亦然:如果您在Lift A
中有某些内容,则可以使用lower
将其降低......呃.. x : Lift A : Set (a ⊔ ℓ)
:lower x : A : Set a
和head
。
我快速搜索了一堆我的代码片段,并提出了这个示例:如何在Vec
转义器上实现安全Vec-ind : ∀ {a p} {A : Set a} (P : ∀ n → Vec A n → Set p)
(∷-case : ∀ {n} x xs → P n xs → P (suc n) (x ∷ xs))
([]-case : P 0 []) →
∀ n (v : Vec A n) → P n v
Vec-ind P ∷-case []-case ._ [] = []-case
Vec-ind P ∷-case []-case ._ (x ∷ xs)
= ∷-case x xs (Vec-ind P ∷-case []-case _ xs)
,仅使用依赖的消除器。这是向量的依赖消除器(也称为归纳原理):
A
由于我们必须处理空向量,我们将使用类型级别函数,对非空向量返回⊤
,对空白向量返回Head : ∀ {a} → ℕ → Set a → Set a
Head 0 A = ⊤
Head (suc n) A = A
:
Set a
但问题是:我们应该返回⊤ : Set
,但Lift
。所以我们Head 0 A = Lift ⊤
Head (suc n) A = A
:
head : ∀ {n a} {A : Set a} → Vec A (suc n) → A
head {A = A} = Vec-ind (λ n xs → Head n A) (λ x _ _ → x) (lift tt) _
然后我们可以写:
{{1}}