与 GHC 的 DataKinds 混在一起,我尝试实现类型级二进制 nats。它们很容易实现,但是如果我希望它们在常见情况下有用,那么 GHC 需要相信Succ
类型族是单射的(因此类型推断至少与一元类型级别一样有效纳特)。但是,我很难说服 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)
case 永远不会返回Bit0 One
,因此Bit1
case 永远不会与 case 冲突One
。同样的论点(“One
不在”的形象中Succ1
)表明它Succ
本身也是单射的。然而,GHC 还不够聪明,无法找到这个论点。
所以,问题:在这种情况下(以及类似的情况),有没有办法让 GHC 相信内射型家族实际上是内射的?(也许是一个类型检查器插件,我可以在其中提供一个反转 Succ1 的函数?也许是一个编译指示说“尝试从这个系列向后推断,就好像它是单射的;如果你遇到任何歧义,你就可以崩溃”?)