我一直在尝试使用Idris,似乎应该很容易指定某种类型来表示两个不同数字之间的所有数字,例如: NumRange 5 10
是5到10之间所有数字的类型。我希望包含双精度/浮点数,但是用整数执行相同操作的类型同样有用。我该怎么做呢?
答案 0 :(得分:9)
在实践中,您可以根据需要简单地检查边界,但您当然可以编写一种数据类型来强制执行此类属性。
一种直截了当的方法就是这样:
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的证明。对于许多临时应用程序来说,这将是一种过度杀伤,但它肯定会显示出如何使用依赖类型来实现此目的。