使用GHC的DataKinds,我尝试实现类型级二进制nat。它们很容易实现,但如果我希望它们在常见情况下有用,那么GHC需要相信Succ
类型族是单射的(因此类型推断至少与它一样有效)对于一元类型级别的nats)。但是,我很难说服GHC这是事实。考虑以下二进制nat编码:
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilyDependencies #-}
module Nat2 where
data Nat = Zero | Pos Nat1
data Nat1 = One | Bit0 Nat1 | Bit1 Nat1
-- by separating Nat and Nat1 we avoid dealing w/ Bit0^n Zero as a spurrious representation of 0
type family Succ (n :: Nat) :: r | r -> n where
Succ 'Zero = 'Pos 'One
Succ ('Pos x) = 'Pos (Succ1 x)
type family Succ1 (n :: Nat1) :: r | r -> n where
Succ1 'One = 'Bit0 'One
Succ1 ('Bit0 x) = 'Bit1 x
Succ1 ('Bit1 x) = 'Bit0 (Succ1 x)
GHC不能接受这一点,因为它无法判断Succ1
是否是单射的:
Nat2.hs:12:3: error:
• Type family equations violate injectivity annotation:
Succ 'Zero = 'Pos 'One -- Defined at Nat2.hs:12:3
Succ ('Pos x) = 'Pos (Succ1 x) -- Defined at Nat2.hs:13:3
• In the equations for closed type family ‘Succ’
In the type family declaration for ‘Succ’
|
12 | Succ 'Zero = 'Pos 'One
| ^^^^^^^^^^^^^^^^^^^^^^
Nat2.hs:16:3: error:
• Type family equations violate injectivity annotation:
Succ1 'One = 'Bit0 'One -- Defined at Nat2.hs:16:3
Succ1 ('Bit1 x) = 'Bit0 (Succ1 x) -- Defined at Nat2.hs:18:3
• In the equations for closed type family ‘Succ1’
In the type family declaration for ‘Succ1’
|
16 | Succ1 'One = 'Bit0 'One
| ^^^^^^^^^^^^^^^^^^^^^^^
我们认为它是单射的,因为通过检查Succ1
,One
永远不在其图像中,因此Bit0 (Succ1 x)
案例永远不会返回Bit0 One
因此,Bit1
案例永远不会与One
案件发生冲突。相同的参数(“One
”的图像中没有“Succ1
”)表明Succ
本身也是单射的。然而,GHC并不十分聪明,无法找到这个论点。
所以,问题:在这种情况下(和这些情况一样),有没有办法说服GHC一个内射型家族实际上是单射的? (也许是一个typechecker插件,我可以在其中提供一个反转Succ1的函数?也许是一个pragma,上面写着“尝试从这个家族向后推断,好像它是单射的;如果你遇到任何歧义,你就可以崩溃”?)