14

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

是否可以以Nat通常的方式定义(通过 Haskell 中的@dorcard Singleton 类型

data S n = Succ n 
data Z   = Zero

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

(或其一些变体),然后定义一个LessThan关系,使得 forallnm

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

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

foo :: Nat (S n) -> Nat n

但这不是我所追求的。

谢谢!

兰吉特。

4

1 回答 1

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的证明。nm

存在主义的解决方法

现在你问:

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。引理说这nS 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
于 2013-07-11T01:00:51.373 回答