使用Haskell编码“小于”

时间:2013-07-10 18:55:35

标签: haskell gadt dependent-type singleton-type

希望一些Haskell专家可以帮助澄清一些事情。

是否可以通常的方式定义Nat(通过@dorchard Singleton types in Haskell

data S n = Succ n 
data Z   = Zero

class Nat n 
instance Nat Z
instance Nat n => Nat (S n)

(或其某些变体)然后定义LessThan关系 如forall nm

LessThan Z (S Z)
LessThan n m => LessThan n     (S m)
LessThan n m => LessThan (S n) (S m)

然后编写一个类似的函数:

foo :: exists n. (LessThan n m) => Nat m -> Nat n
foo (S n) = n
foo Z     = foo Z

我明确地希望在foo的输出类型中使用“LessThan”, 我意识到人们当然可以写出像

这样的东西
foo :: Nat (S n) -> Nat n

但那不是我追求的目标。

谢谢!

兰吉特。

1 个答案:

答案 0 :(得分:17)

这是实现类似于你所要求的东西的一种方法。

纳特

首先请注意,您将Nat定义为类,然后将其用作类型。我认为将它作为一种类型是有意义的,所以让我们这样定义它。

data Z
data S n

data Nat n where
  Zero :: Nat Z
  Succ :: Nat n -> Nat (S n)

每种不超过

我们还可以将LessThan定义为类型。

data LessThan n m where
  LT1 :: LessThan Z (S Z)
  LT2 :: LessThan n m -> LessThan n (S m)
  LT3 :: LessThan n m -> LessThan (S n) (S m)

请注意,我只是将您的三个属性转换为数据构造函数。这种类型的想法是LessThan n m类型的完全标准化值证明n小于m

解决存在问题

现在你问:

foo :: exists n. (LessThan n m) => Nat m -> Nat n

但Haskell中不存在。相反,我们可以为foo定义数据类型:

data Foo m where
  Foo :: Nat n -> LessThan n m -> Foo m

请注意n在这里有效地存在量化,因​​为它显示在数据构造函数Foo的参数中,但不会显示在其结果中。现在我们可以说明foo

的类型
foo :: Nat m -> Foo m

引理

在我们能够从问题中实现示例之前,我们必须证明LessThan的一个小问题。引理说n对于所有S n都小于n。我们通过n上的归纳证明了这一点。

lemma :: Nat n -> LessThan n (S n)
lemma Zero = LT1
lemma (Succ n) = LT3 (lemma n)

foo的实施

现在我们可以编写问题的代码:

foo :: Nat m -> Foo m
foo (Succ n) = Foo n (lemma n)
foo Zero = foo Zero