Agda 中的 Arity 通用编程

2023-11-24

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


我将以 n 元复合函数为例。

最简单的版本

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 module:

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

I.e. comp收到一个号码n,一个函数g : Y -> Z和一个函数f,其数量为n以及结果类型Y.

In the comp 0 g y = {!!}我们有的情况

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

因此这个洞可以很容易地被填补g y.

In the comp (suc n) g f = {!!} case, N-ary (suc n) X Y减少到X -> N-ary n X Y and 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)

I.e. comp收到n类型参数X, 适用f给他们,然后应用g到结果。

最简单的版本,带有依赖项g

When 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 to 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)

And comp then is

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)

具有不同类型参数的版本

有“Arity-通用数据类型-通用编程” 论文,除其他外,描述了如何编写接收不同类型参数的 arity-generic 函数。其想法是将类型向量作为参数传递,并以以下方式折叠它:N-ary:

arrTy : {n : N} → Vec Set (suc n) → Set
arrTy {0}     (A :: []) = A
arrTy {suc n} (A :: As) = A → arrTy As

然而,即使我们提供了向量的长度,Agda 也无法推断出该向量。因此,本文还提供了一个用于柯里化的运算符,它由一个函数组成,该函数显式接收一个类型向量,一个函数,该函数接收n隐式参数。

这种方法有效,但它不能扩展到完全宇宙多态函数。我们可以通过替换来避免所有这些问题Vec数据类型与_^_操作员:

_^_ : ∀ {α} -> Set α -> ℕ -> Set α
A ^ 0     = Lift ⊤
A ^ suc n = A × A ^ n

A ^ n同构于Vec A n。然后我们的新N-ary is

_->ⁿ_ : ∀ {n} -> Set ^ n -> Set -> Set
_->ⁿ_ {0}      _      B = B
_->ⁿ_ {suc _} (A , R) B = A -> R ->ⁿ B

所有类型都位于Set为了简单起见。comp now is

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

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

Sets : ∀ {n} -> (αs : Level ^ n) -> ∀ β -> Set (mono-^ (map lsuc) αs ⊔ⁿ lsuc β)
Sets {0}      _       β = Set β
Sets {suc _} (α , αs) β = Σ (Set α) λ X -> X -> Sets αs β

第二种情况看起来像“有一种类型X这样所有其他类型都依赖于一个元素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 and g now?

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, but Ynow 隐藏在这些嵌套依赖对的末尾,并且可以依赖于任何X from Xs. Z以前有类型Y -> Set γ,因此现在我们需要附加Set γ to Xs,使得所有x隐式:

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

OK, 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)

A test:

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₁, while and A lie in Set——这说明了宇宙的多态性。

Remarks

AFAIK,对于隐式参数没有可理解的理论,所以我不知道,当第二个函数(即f) 接收隐式参数。本次测试:

foo' : ∀ {α} {A : Set α} -> ℕ -> A -> ℕ
foo' = comp 2 length (λ n -> replicate {n = n})

test' : foo' 5 true ≡ 5
test' = refl

至少通过了。

comp如果某种类型所在的宇宙依赖于一个值,则无法处理函数。例如

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'

但这对于 Agda 来说很常见,例如你不能明确应用id对自己:

idₑ : ∀ α -> (A : Set α) -> A -> A
idₑ _ _ x = x

-- ... because this would result in an invalid use of Setω ...
error = idₑ _ _ idₑ

The code.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Agda 中的 Arity 通用编程 的相关文章

  • 根据参数值返回不同类型的通用函数

    我有一个保存寄存器的结构 我想要我的read register函数返回一个u8 for Register V0 and Register V1 but a u16 for Register V2 and Register V3 我不确定如何
  • 将 Map[String, Any] 转换为 case 类的无形状代码无法处理可选子结构

    我正在尝试使用这个https stackoverflow com a 31641779 1586965 https stackoverflow com a 31641779 1586965 如何使用 shapeless 将泛型 Map St
  • 类型参数和索引之间的区别?

    我是依赖类型的新手 对两者之间的区别感到困惑 似乎人们通常说类型是由另一种类型参数化 and 按某个值索引 但是 在依赖类型语言中 类型和术语之间不是没有区别吗 参数和指数之间的区别是根本性的吗 您能否举例说明它们在编程和定理证明中的含义差
  • F# 类型提供程序相关的嵌套类型

    我正在尝试构建一个嵌套的 TypeProviderProvidedProperty根据父级的类型值生成 我想要的结果如下 r bin Debug library dll open Library TypeProviders type sdm
  • 用约翰·梅杰的等式重写

    约翰 梅杰的等式带有以下重写引理 Check JMeq ind r JMeq ind r forall A Type x A P A gt Prop P x gt forall y A JMeq y x gt P y 很容易将其概括为 Le
  • 在没有 @RequestParam 名称的控制器中获取文件

    我正在尝试构建一个通用的 POST 控制器 我可以以通用方式访问参数 但如果不使用 RequestParam files MultipartFile 文件 我就无法获取可能的文件 所以 有人知道如何以通用方式获取文件 如果有提交的话 吗 到
  • 直觉类型理论的组合逻辑等价物是什么?

    我最近完成了一门以 Haskell 和 Agda 一种依赖类型函数编程语言 为特色的大学课程 并且想知道是否有可能用组合逻辑代替其中的 lambda 演算 在 Haskell 中 使用 S 和 K 组合器似乎可以实现这一点 从而使其成为无点
  • 在scala shapeless中,是否可以使用文字类型作为泛型类型参数?

    假设我正在编写一个向量乘法程序 按照本文的要求 https etrain github io 2015 05 28 type safe 线性 algebra in scala https etrain github io 2015 05 2
  • 依赖类型:依赖对类型与不相交联合有何相似之处?

    我一直在研究依赖类型 我了解以下内容 Why 通用量化 https en wikipedia org wiki Universal quantification被表示为依赖函数类型 x A B x means 对全部x类型的A有一个类型的值
  • 我可以使用作用域枚举来通过模板进行 C++ 标记调度吗?

    模板新手在这里 我正在尝试以下代码 include
  • 将排序列表与大小类型合并

    假设我们有一个排序列表的数据类型 具有与证明无关的排序见证 我们将使用 Agda 的实验性大小类型功能 这样我们就有希望在数据类型上获得一些递归函数来通过 Agda 的终止检查器 OPTIONS sized types open impor
  • Java 中泛型类型的深度复制

    泛型类型的深拷贝 克隆 是如何实现的T E在 Java 中工作 是否可以 E oldItem E newItem olditem clone does not work 答案是不 因为无法找出哪个类将取代您的泛型类型E在编译时 除非你将其绑
  • 由 Scala 宏生成时,依赖类型似乎“不起作用”

    为这个挥手的标题道歉 我不完全确定如何简洁地表达这个问题 因为我以前从未遇到过这样的事情 背景资料 我有以下特征 其中类型U是为了举行无形可扩展记录 https github com milessabin shapeless wiki Fe
  • 使用 C++ 自动 Lua 绑定

    我正在构建一个简单的 2D 游戏引擎 它变得越来越大 暴露 Lua 中的所有功能将是不可能的 所以我试图自动化一点这个过程 无论如何 是否可以一次从堆栈中获取所有 n 个参数 具有不同类型 并将它们直接注入到 C 函数中 我已经自动化了函数
  • 嵌套名称说明符

    我有一个类似的代码 namespace mymap template
  • 持有泛型类型的实例 - C++

    我有一个tree node类和一个tree class template
  • 如何学习阿格达

    我正在努力学习agda 但是 我遇到了一个问题 我在 agda wiki 上找到的所有教程对我来说都太复杂了 并且涵盖了编程的不同方面 在并行阅读了 3 个关于 agda 的教程后 我能够编写简单的证明 但我仍然没有足够的知识来使用它来实现
  • 指向具有不同参数的成员函数的指针的容器

    我到处寻找 现代 C 设计和合作 但我找不到一种好方法来存储一组接受不同参数并对不同类进行操作的回调 我需要这个 因为我希望应用程序的每个对象都有可能将其方法之一的执行推迟到主对象Clock对象 跟踪当前时间 可以在正确的时刻调用此方法 我
  • 为什么较新的依赖类型语言没有采用 SSReflect 的方法?

    我在 Coq 的 SSReflect 扩展中发现了两个约定 它们似乎特别有用 但我还没有看到它们在较新的依赖类型语言 Lean Agda Idris 中得到广泛采用 首先 可能的谓词被表示为布尔返回函数而不是归纳定义的数据类型 默认情况下
  • 多个结构体,需要在方法中访问相同的字段

    我目前尝试用 C 语言编写一些简单的控制台游戏来娱乐 为此 我需要能够在 嗯 C 中打印类似窗口的结构 我想使用通用渲染方法 让我们称之为frame render 渲染所有不同的 ui 元素 现在的问题是 如何解决这个问题 给定场景 The

随机推荐