有限数字如何工作? (依赖类型)

时间:2013-09-10 18:17:33

标签: agda dependent-type idris

我对依赖类型语言感兴趣。有限数字对我来说似乎非常有用。例如,安全地索引固定大小的数组。但这个定义对我来说并不清楚。

Idris中有限数据的数据类型如下:(并且在Agda中可能类似)

data FiniteNum : Natural -> Type where
  FZero : FiniteNum (Succ k)
  FSucc : FiniteNum k -> FiniteNum (Succ k)

似乎有效:

exampleFN : FiniteNum (Succ (Succ Zero))
exampleFN = FSucc FZero -- typechecks
-- exampleFN = FSucc (FSucc FZero)  -- won't typecheck

但这是如何运作的? k是什么意思?为什么类型检查器接受第一个实现并拒绝第二个?

2 个答案:

答案 0 :(得分:9)

将索引视为可以由Fin n表示的任何数字的上限。例如,Fin 4包含小于4的所有自然数。这是一个数据声明:

data Fin : ℕ → Set where

该定义与此有何关系?自然数的定义有两部分:zerosuc;对于Fin,我们会调用fzerofsuc

使用我们的上限解释,fzero可以给出任何上限,只要它不是zero(0≮0)。我们如何表示绑定可以是zero以外的任何其他内容?我们可以通过应用suc

来强制执行此操作
fzero : {k : ℕ} → Fin (suc k)

这正是我们所需要的:没有人能够以fzero类型的方式编写Fin 0

现在fsuc案例:我们有一个上限为k的数字,我们想要创建一个后继者。关于上限我们能说些什么?肯定会增加至少一个:

fsuc : {k : ℕ} → Fin k → Fin (suc k)

作为练习,请说服自己所有小于n的数字都可以用Fin n表示(只有一种可能的方式)。


类型检查器如何接受并拒绝另一个?在这种情况下,它是简单的统一。我们来看看这段代码:

test : Fin (suc (suc zero))
test = ?

当我们写fsuc时,Agda必须弄清k的值。要做到这一点,需要查看fsuc构造函数:它构造一个Fin (suc k)类型的值,我们需要suc k = suc (suc zero);通过统一这两个,我们得到k = suc zero。所以接下来:

test = fsuc ?

现在,fsuc后面的表达式(由?表示, hole )的表达式为Fin (suc zero)(自k = suc zero起)。当我们填写fzero时,Agda会尝试将suc zerosuc k₂统一起来,这当然会成功解决k₂ = zero

如果我们决定投入另一个fsuc

test = fsuc (fsuc ?)

然后使用与上面相同的统一,我们得到洞的类型必须是Fin zero。到目前为止,这种类型检查很好。但是,当您尝试将fzero填入其中时,Agda必须将zerosuc k₃统一起来 - 无论k₃suc的价值如何永远不会是zero,因此失败并且您会收到类型错误。


有限数的另一种表示(可以说是不太适合使用)是一对自然数,并证明它小于界限。

open import Data.Product

Fin' : ℕ → Set
Fin' n = Σ ℕ (λ k → k < n)

原始Fin可以被视为Fin'的版本,其中证明直接烘焙到构造函数中。

答案 1 :(得分:1)

简短的回答是FiniteNum Zero类型为空,因为两个构造函数都返回以非零自然数索引的FiniteNum。现在尝试回答以下问题:FiniteNum(Succ Zero)有多少个元素?他们看起来怎么样?重复2,3,4 ...