如何在 Idris 中将数字范围指定为类型?

How to specify a number range as a type in Idris?

我一直在试验 Idris,似乎指定某种类型来表示两个不同数字之间的所有数字应该很简单,例如NumRange 5 10 是 5 到 10 之间所有数字的类型。我想包括 doubles/floats,但是对整数执行相同操作的类型同样有用。我该怎么做?

在实践中,根据需要简单地检查边界可能会更好,但您当然可以编写数据类型来强制执行这样的 属性。

一个简单的方法是这样的:

data Range : Ord a => a -> a -> Type where
  MkRange : Ord a => (x,y,z : a) -> (x >= y && (x <= z) = True) -> Range y z

我已经在 Ord 类型类上通用地编写了它,但您可能需要专门化它。范围要求以方程式表示,因此您只需在构造它时提供 Refl,然后将检查 属性。例如:MkRange 3 0 10 Refl : Range 0 10。这样的事情的一个缺点是必须提取包含的值的不便。当然,如果您想以编程方式构建实例,则需要提供确实满足边界的证明,或者在某些允许失败的上下文中进行,例如 Maybe.

我们可以毫不费力地为 Nat 编写一个更优雅的示例,因为对于它们我们已经有一个库数据类型来表示比较证明。特别是 LTE,表示小于或等于。

data InRange : Nat -> Nat -> Type where
  IsInRange : (x : Nat) -> LTE n x -> LTE x m -> InRange n m

现在这种数据类型很好地封装了 n ≤ x ≤ m 的证明。对于许多随意的应用程序来说,这可能有点矫枉过正,但它确实展示了您可以如何为此目的使用依赖类型。