Haskell/Idris中的开放式水平证明

Haskell/Idris中的开放式水平证明,haskell,proof,category-theory,correctness,idris,Haskell,Proof,Category Theory,Correctness,Idris,在Idris/Haskell中,可以通过注释类型和使用GADT构造函数(例如使用Vect)来证明数据的属性,但是,这需要将属性硬编码到类型中(例如,Vect必须是列表中的单独类型)。 有没有可能使类型具有一组开放的属性(例如同时包含长度和运行平均数的列表),例如通过重载构造函数或使用某种效果?我相信McBride在他的文章中回答了这个问题(对于类型理论)。您正在寻找的概念是代数装饰(强调我的): 代数φ描述了解释数据的结构化方法,给出了 递归地应用该方法,进行折叠运算。 毫不奇怪,生成的φ调用树

在Idris/Haskell中,可以通过注释类型和使用GADT构造函数(例如使用Vect)来证明数据的属性,但是,这需要将属性硬编码到类型中(例如,Vect必须是列表中的单独类型)。
有没有可能使类型具有一组开放的属性(例如同时包含长度和运行平均数的列表),例如通过重载构造函数或使用某种效果?

我相信McBride在他的文章中回答了这个问题(对于类型理论)。您正在寻找的概念是代数装饰(强调我的):

代数φ描述了解释数据的结构化方法,给出了 递归地应用该方法,进行折叠运算。 毫不奇怪,生成的φ调用树具有相同的 结构作为原始数据-这毕竟是重点。但是 如果这是重点呢?假设我们想修好这个房间 预先折叠φ的结果,仅表示将 提供我们想要的答案。我们应该需要数据来符合 提供答案的电话树我们可以限制我们的数据吗 到底是什么意思?当然可以,如果我们根据答案编制索引。

现在,让我们编写一些代码。我把整件事都放在这里,因为我要在这里插入评论。此外,我正在使用Agda,但它应该很容易传输到Idris

module reornament where
我们首先定义什么是作用于
a
s列表的
B
s代数。我们需要一个基本情况(类型为
B
)以及将列表的开头与归纳假设相结合的方法

ListAlg : (A B : Set) → Set
ListAlg A B = B × (A → B → B)
根据此定义,我们可以定义一类由
B
s索引的
a
s列表,其值正好是与给定
ListAlg a B
对应的计算结果。在
nil
情况下,结果是代数(
proj)提供给我们的基本情况₁ alg
)在
cons
情况下,我们只需使用第二个投影将归纳假设与新头部相结合:

data ListSpec (A : Set) {B : Set} (alg : ListAlg A B) : (b : B) → Set where
  nil  :  ListSpec A alg (proj₁ alg)
  cons : (a : A) {b : B} (as : ListSpec A alg b) → ListSpec A alg (proj₂ alg a b)
好的,现在让我们导入一些库并查看几个示例:

open import Data.Product
open import Data.Nat
open import Data.List
计算列表长度的代数由
0
作为基本情况给出,而
const suc
作为组合
a
和尾部长度以构建当前列表长度的方法给出。因此:

AlgLength : {A : Set} → ListAlg A ℕ
AlgLength = 0 , (λ _ → suc)
如果元素是自然数,那么它们可以求和。与之对应的代数将
0
作为基本情况,并将
\uu+
作为组合
以及尾部包含的元素的总和。因此:

AlgSum : ListAlg ℕ ℕ
AlgSum = 0 , _+_
疯狂的想法:如果我们有两个代数在同一个元素上工作,我们可以组合它们!这样我们将跟踪2个不变量,而不是一个

Alg× : {A B C : Set} (algB : ListAlg A B) (algC : ListAlg A C) →
       ListAlg A (B × C)
Alg× (b , sucB) (c , sucC) = (b , c) , (λ a → λ { (b , c) → sucB a b , sucC a c })
下面是一个例子:

如果我们跟踪长度,那么我们可以定义向量:

Vec : (A : Set) (n : ℕ) → Set
Vec A n = ListSpec A AlgLength n
并且具有,例如,长度为4的向量:

allFin4 : Vec ℕ 4
allFin4 = cons 0 (cons 1 (cons 2 (cons 3 nil)))
如果我们跟踪元素的总和,那么我们可以定义分布的概念:统计分布是一个概率列表,其总和为100:

Distribution : Set
Distribution = ListSpec ℕ AlgSum 100
我们可以定义一个统一的,例如:

uniform : Distribution
uniform = cons 25 (cons 25 (cons 25 (cons 25 nil)))
最后,通过结合长度和和代数,我们可以实现大小分布的概念

SizedDistribution : ℕ → Set
SizedDistribution n = ListSpec ℕ (Alg× AlgLength AlgSum) (n , 100)
对于4个元素集,给出一个很好的均匀分布:

uniform4 : SizedDistribution 4
uniform4 = cons 25 (cons 25 (cons 25 (cons 25 nil)))

这太棒了。我写了一篇伊德里斯的译文:@BrianMcKenna真是太棒了。是否有可能将异质列表表示为这样的装饰?还是增加名单?@SamuraiJack当然。您需要找到一种要存储在列表中的对象类型,以及相应的
fold
从元素列表中计算不变量。我得到的是:@gallais看起来很酷,谢谢!布莱恩·麦肯纳:伊德里斯翻译的可能性有吗?:)