适当使用宇宙多态性

时间:2014-01-06 23:49:01

标签: set hierarchy agda parametric-polymorphism

我已经在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

1 个答案:

答案 0 :(得分:2)

我认为你不能将它推广到任意的Universe级别,并且仍然可以编译quibble。二元关系的乘积可以非常容易地推广:你只需要为SetA每种类型用一个字母装饰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(和yxsys)的类型为A : Set ax≈y的类型为x ≈ y : Rel A ℓ = A → A → Set ℓ。这意味着构造函数的类型应为Set (max a ℓ),或标准库表示法Set (a ⊔ ℓ)

是的,如果我们将≈-List概括为与A : Set a一起使用,我们必须将其类型声明为Rel (List A) (a ⊔ ℓ)。如果没有Rel (List A) ℓxyxs,您可以将其设为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,则可以通过liftlift a : Lift A : Set (a ⊔ ℓ)移至更高级别,反之亦然:如果您在Lift A中有某些内容,则可以使用lower将其降低......呃.. x : Lift A : Set (a ⊔ ℓ)lower x : A : Set ahead


我快速搜索了一堆我的代码片段,并提出了这个示例:如何在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}}