为了处理某些网络协议,我一直在使用GHC.TypeLits
来实现固定大小的位向量作为用Nat
类型标记的包裹整数。
newtype W (n :: Nat) = W { getW :: Integer }
除了各种类(Integral,Num,Bits等)的实例外,我还定义了一个函数来组合它们:
(>+<) :: forall n m. (KnownNat m, KnownNat n, KnownNat (m + n)) => W m -> W n -> W (m + n)
(W x) >+< (W y) = fromInteger $ x + shift y (natValInt (Proxy :: Proxy m))
下一部分是我遇到麻烦的地方。我正在尝试创建一个导致W n
的应用,导致W m
,其中m
是n
的除数。例如,使用attoparsec,应该能够写:
anyWord128 :: Parser (W 128)
anyWord128 = assemble $ fmap (fromIntegral :: Word8 -> W 8) anyWord8
这是我的尝试:
class (KnownNat d, KnownNat n) => d :|: n where
assemble :: forall f. Applicative f -> f (W d) -> f (W n)
instance KnownNat n => n :|: n where
assemble = id
instance (KnownNat n, CmpNat n d ~ GT, d :|: n', (d + n') ~ n) => d :|: n where
assemble f = liftA2 (>+<) f (assemble f)
代码编译(包含许多语言扩展,包括-XOverlappingInstances,所有这些都在下面链接的实际源中),加载assemble
的示例用法会导致GHCi告诉我{的实例重叠{1}}。我猜这是因为我不知道自己在做什么,或者因为GHC的类型检查程序的计算能力有限(或两者兼而有之)。
你们中的任何一个GHC向导都能看到正确定义这个类的方法吗?
修改
固定类型的汇编定义 - 谢谢kosmikus
此外,这里是完整的source(第{159行)定义了8 :|: 8
。