确保终止时的类型级别固定点

时间:2019-01-04 04:31:46

标签: idris

有可能代表如何使unFix总计?可能通过限制f是什么?

record Fix (f : Type -> Type) where
    constructor MkFix
    unFix : f (Fix f)

> :total unFix
Fix.unFix is possibly not total due to:
    MkFix, which is not strictly positive

1 个答案:

答案 0 :(得分:7)

这里的问题是Idris无法知道您用于数据类型的基本函子严格为正。如果要接受您的定义,则可以将其与具体的负函子一起使用,并从中证明Void

有两种方法表示严格的正函子:通过定义Universe或使用容器。我已将所有内容都放在two self-contained gists中(但那里没有评论)。

一个严格正函子的宇宙

您可以从基本表示开始:我们可以将函子分解为sigma类型(Sig),递归子结构(Rec)的(严格正值)位置或不分解为全部(End)。这为我们提供了此描述及其作为Type -> Type函数的解码:

-- A universe of positive functor
data Desc : Type where
  Sig : (a : Type) -> (a -> Desc) -> Desc
  Rec : Desc -> Desc
  End : Desc


-- The decoding function
desc : Desc -> Type -> Type
desc (Sig a d) x = (v : a ** desc (d v) x)
desc (Rec d)   x = (x, desc d x)
desc End       x = ()

一旦您拥有此函子的范围,并且保证它们是严格肯定的,就可以采用其最小定点:

-- The least fixpoint of such a positive functor
data Mu : Desc -> Type where
  In : desc d (Mu d) -> Mu d

您现在可以定义自己喜欢的数据类型。

示例:Nat

我们从每个构造函数的标签的总和类型开始。

data NatC = ZERO | SUCC

然后,通过将构造函数标签存储在sigma中并基于标签值计算其余描述,来定义严格的正基函子。 ZERO标记与End相关联(zero构造函数中没有其他可存储的东西),而SUCC则需要一个Rec End,即说一个与Nat的前任相对应的递归子结构。

natD : Desc
natD = Sig NatC $ \ c => case c of
  ZERO => End
  SUCC => Rec End

然后通过获取描述的固定点来获得我们的归纳类型:

nat : Type
nat = Mu natD

我们自然可以恢复我们期望的构造函数:

zero : nat
zero = In (ZERO ** ())

succ : nat -> nat
succ n = In (SUCC ** (n, ()))

参考文献

这个特定的宇宙来自McBride的“装饰代数,代数装饰”,但您可以在Chapman,Dagand,McBride和Morris的“ The Livitation of Levitation”中找到更多详细信息。

严格正函子作为容器的扩展

第二种表示形式是基于另一种分解的:每个归纳类型都被视为一般形状(即其构造函数和它们存储的数据)加上许多递归位置(这可能取决于形状的特定值)。

record Container where
  constructor MkContainer
  shape : Type
  position : shape -> Type

再一次,我们可以将其解释为Type -> Type函数:

container : Container -> Type -> Type
container (MkContainer s p) x = (v : s ** p v -> x)

并使用由此定义的严格正函子的固定点:

data W : Container -> Type where
  In : container c (W c) -> W c

通过定义感兴趣的Container,您可以再次恢复自己喜欢的数据类型。

示例:Nat

自然数有两个构造函数,每个构造函数根本不存储任何内容。因此形状将为Bool。如果我们处于zero情况下,则没有递归位置(Void),而在succ中有一个递归位置(())。

natC : Container
natC = MkContainer Bool (\ b => if b then Void else ())

我们的类型是通过获取容器的固定点获得的:

nat : Type
nat = W natC

我们可以恢复通常的构造函数:

zero : nat
zero = In (True ** \ v => absurd v)

succ : nat -> nat
succ n = In (False ** \ _ => n)

参考文献

这是基于Abbott,Altenkirch和Ghani的“容器:构造严格的正类型”。