有可能代表一些如何制作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
Run Code Online (Sandbox Code Playgroud)
这里的问题是Idris无法知道您为数据类型使用的基本仿函数是严格正的.如果它接受你的定义,那么你可以将它与一个具体的,负面的仿函数一起使用并Void
从中证明.
有两种方法可以表示严格的正面仿函数:通过定义Universe或使用容器.我把所有东西放在两个独立的要点(但那里没有评论).
您可以从一个基本表示开始:我们可以将一个仿函数分解为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 = ()
Run Code Online (Sandbox Code Playgroud)
一旦你拥有这个保证严格肯定的仿函数,你可以采用它们最少的修复点:
-- The least fixpoint of such a positive functor
data Mu : Desc -> Type where
In : desc d (Mu d) -> Mu d
Run Code Online (Sandbox Code Playgroud)
您现在可以定义自己喜欢的数据类型.
我们从每个构造函数的标记类型开始.
data NatC = ZERO | SUCC
Run Code Online (Sandbox Code Playgroud)
然后,我们通过将构造函数标记存储在sigma中并基于标记值计算其余描述来定义严格正基础仿函数.该ZERO
标签被关联到End
(有没有别的在存储zero
构造函数),而SUCC
一个需要一个Rec End
,即对应于NAT的前身一个递归子.
natD : Desc
natD = Sig NatC $ \ c => case c of
ZERO => End
SUCC => Rec End
Run Code Online (Sandbox Code Playgroud)
然后通过描述的固定点获得我们的归纳类型:
nat : Type
nat = Mu natD
Run Code Online (Sandbox Code Playgroud)
我们可以自然地恢复我们期望的构造函数:
zero : nat
zero = In (ZERO ** ())
succ : nat -> nat
succ n = In (SUCC ** (n, ()))
Run Code Online (Sandbox Code Playgroud)
这个特定的宇宙取自McBride的"Ornamental Algebras,Algebraic Ornaments",但你可以在Chapman,Dagand,McBride和Morris的"The Lentle Art of Levitation"中找到更多细节.
第二种表示基于另一种分解:每种归纳类型被视为一般形状(即它的构造函数和它们存储的数据)加上一些递归位置(可以取决于形状的特定值).
record Container where
constructor MkContainer
shape : Type
position : shape -> Type
Run Code Online (Sandbox Code Playgroud)
我们再一次可以给它一个解释作为一个Type -> Type
函数:
container : Container -> Type -> Type
container (MkContainer s p) x = (v : s ** p v -> x)
Run Code Online (Sandbox Code Playgroud)
并采用如此定义的严格正仿函数的固定点:
data W : Container -> Type where
In : container c (W c) -> W c
Run Code Online (Sandbox Code Playgroud)
您可以通过定义Container
感兴趣的内容再次恢复您喜欢的数据类型.
自然数有两个构造函数,每个构造函数都没有存储.所以形状将是一个Bool
.如果我们在这种zero
情况下那么没有递归位置(Void
),并且在那个succ
中只有一个(()
).
natC : Container
natC = MkContainer Bool (\ b => if b then Void else ())
Run Code Online (Sandbox Code Playgroud)
我们的类型是通过获取容器的固定点获得的:
nat : Type
nat = W natC
Run Code Online (Sandbox Code Playgroud)
我们可以恢复通常的构造函数:
zero : nat
zero = In (True ** \ v => absurd v)
succ : nat -> nat
succ n = In (False ** \ _ => n)
Run Code Online (Sandbox Code Playgroud)
这是基于Abbott,Altenkirch和Ghani的"容器:构建严格正面类型".