haskell - 用 Haskell 编码 "Less Than"

标签 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 关系 这样对于所有 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

但这不是我所追求的。

谢谢!

兰 git 。

最佳答案

这是一种实现与您所询问的内容类似的方法。

纳特

首先请注意,您将 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 nm 类型的完全标准化值是 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 的引理。该引理表明,对于所有 nn 都小于 S 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

关于haskell - 用 Haskell 编码 "Less Than",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17578728/

相关文章:

haskell - Haskell 有善统一吗?

haskell - 不寻常的种类和数据构造函数

haskell - 避免捕获替换函数 — Lambda 演算

haskell - 是否可以编写一个函数 Int -> NatSing n,其中 NatSing 是单例类型的皮亚诺数?

Haskell: (+1) 和 (\x->x+1) 有什么区别?

haskell - 如何使用函数依赖和存在量化来为我的类型删除不必要的参数

Haskell:如何测试未编译的代码?

haskell - Idris 中依赖类型的限制

testing - Haskell 测试框架 (HTF) 和多个模块中的测试定义

haskell - 如何更新元组列表中的某个元组元素?