添加类型级别自然数

时间:2013-01-28 11:29:02

标签: haskell dependent-type

我假设,不可能在haskell中添加两个类型级自然数。这是真的?

假设自然数的定义如下:

class HNat a

data HZero
instance HNat HZero

data HSucc n
instance (HNat n) => HNat (HSucc n)

以类似于:

的方式定义HAdd是否合适
class (HNat n1, HNat n2, HNat ne) => HAdd n1 n2 ne | n1 n2 -> ne
instance             HAdd HZero HZero HZero
instance (HNat x) => HAdd HZero x     x
instance (HNat n1 
         ,HNat x) => HAdd (HSucc n1)  x (HAdd n1 (HSucc x) (???))

2 个答案:

答案 0 :(得分:20)

您无需添加HZeroHZero的情况。第二种情况已经涵盖了这一点。想想你如何通过对第一个论点的归纳来在术语水平上添加Peano自然:

 data Nat = Zero | Succ Nat

 add :: Nat -> Nat -> Nat
 add Zero     y = y
 add (Succ x) y = Succ (add x y)

现在,如果您正在使用函数依赖项,那么您正在编写逻辑程序。因此,不要在右侧进行递归调用,而是在左侧为递归调用的结果添加约束:

 class (HNat x, HNat y, HNat r) => HAdd x y r | x y -> r
 instance (HNat y)     => HAdd HZero     y y
 instance (HAdd x y r) => HAdd (HSucc x) y (HSucc r)

第二个实例中不需要HNat约束。它们被类中的超类约束所暗示。

现在,我认为进行这种类型级编程的最好方法是使用DataKindsTypeFamilies。您在术语级别上定义:

 data Nat = Zero | Succ Nat

然后,您可以将Nat不仅用作类型,还可以用作种类。然后,您可以在两个自然数上定义类型系列,如下所示:

 type family Add (x :: Nat) (y :: Nat) :: Nat
 type instance Add Zero     y = y
 type instance Add (Succ x) y = Succ (Add x y)

这更接近添加的术语级定义。此外,使用“提升”类Nat可以使您不必定义HNat等类。

答案 1 :(得分:3)

有可能。查看包type-level-natural-number`type-level-natural-number-operations。两者都有点旧,但易于使用,后者定义了Plus类型系列。

无论如何,我会将你的最后一行更改为这样的东西(我没有测试是否编译)。

instance (HNat n1, HNat x, HAdd n1 x y) => HAdd (HSucc n1) x (HAdd n1 x (HSucc y))

基本上,你所做的是以归纳方式定义加法,而附加约束HAdd n1 x y增加了必要的归纳案例。